skip to Main Content

I’m working on a Durable Functions setup where I have a timer trigger orchestrating a sequence of activities. However, I’m facing an issue with the logging sequence. Currently, the "Completed" log appears immediately after the timer trigger, but I want it to appear only after the entire orchestration sequence, including all sub-orchestrations, is completed. Below is a simplified version of my code:



[Function("TimerTrigger_EveryMinute")]
public async Task TimerTrigger_EveryMinute(
    [TimerTrigger("0 * * * * *")] TimerInfo timerInfo,
    [DurableClient] DurableTaskClient starter)
{
    _logger.LogError($"Running timer trigger");

    string instanceId = await starter.StartNewAsync("MainOrchestrator", null);

    // Wait for the entire orchestration to complete
    await starter.WaitForInstanceCompletionAsync(instanceId);

    _logger.LogError($"Completed timer trigger orchestration with ID = '{instanceId}'");
}

[Function("MainOrchestrator")]
public async Task MainOrchestrator(
    [OrchestrationTrigger] DurableOrchestrationContext context)
{
    _logger.LogError($"Running MainOrchestrator");

    var tasks = new List<Task>();

    List<TransactionData> transactions = new List<TransactionData>();

    // Call suborchestrator for each ongoing transaction
    foreach (var transaction in transactions)
    {
        tasks.Add(context.CallSubOrchestratorAsync("SubOrchestrator", transaction));
    }

    await Task.WhenAll(tasks);
}

[Function("SubOrchestrator")]
public async Task SubOrchestrator(
    [OrchestrationTrigger] DurableOrchestrationContext context, TransactionData transaction)
{
    _logger.LogError($"Running SubOrchestrator");

    // other logic here
}

Output

In this setup, the logs are showing "Completed" immediately after the timer trigger logs, but I want it to appear only after all orchestrations, including sub-orchestrations, are completed.

2

Answers


  1. Chosen as BEST ANSWER

    The MainOrchestrator function seems to be invoked multiple times in quick succession, leading to unexpected behavior in my application. I expect it to be invoked only once per timer trigger. Could someone help me understand why this is happening and how I can ensure that the MainOrchestrator function is invoked only once per timer trigger?

     [Function("TimerTrigger_EveryMinute")]
            public async Task TimerTrigger_EveryMinute(
            [TimerTrigger("0 * * * * *")] TimerInfo timerInfo,
            [DurableClient] DurableTaskClient starter)
            {
                _logger.LogError($"Running timer trigger");
     
                string instanceId = await starter.ScheduleNewOrchestrationInstanceAsync("MainOrchestrator", null);
                await starter.WaitForInstanceCompletionAsync(instanceId);
     
                _logger.LogError($"Completed timer trigger orchestration with ID = '{instanceId}'");
            }
     
            [Function("MainOrchestrator")]
            public async Task MainOrchestrator(
                [OrchestrationTrigger] TaskOrchestrationContext context)
            {
                ILogger log = context.CreateReplaySafeLogger("MainOrchestrator");
                log.LogError("Calling Running MainOrchestrator");
                _logger.LogError($"Running MainOrchestrator");
                var tasks = new List<Task>();
     
                List<TransactionData> transactions = new List<TransactionData>();
     
                log.LogError("before for loop");
                for (var transaction = 0; transaction < 2; transaction++)
                {
                    log.LogError("inside for loop");
                    tasks.Add(context.CallSubOrchestratorAsync("SubOrchestrator", transaction));
                }
     
                log.LogError("Calling after for loop");
                await Task.WhenAll(tasks);
            }
     
            [Function("SubOrchestrator")]
            public async Task SubOrchestrator(
                [OrchestrationTrigger] TaskOrchestrationContext context, int transaction)
            {
                ILogger log = context.CreateReplaySafeLogger("SubOrchestrator");
                log.LogError("Calling SubOrchestrator");
                _logger.LogError($"Running SubOrchestrator");
            }
     
           
        }
        public class TransactionData
        {
            public string TransactionId { get; set; }
            public string TransactionType { get; set; }
        }
    

    enter image description here


  2. I have modified your code a bit and it worked as expected.

    using Microsoft.Azure.Functions.Worker;
    using Microsoft.Azure.Functions.Worker.Http;
    using Microsoft.DurableTask;
    using Microsoft.DurableTask.Client;
    using Microsoft.Extensions.Logging;
    using System.Transactions;
    
    namespace _78332074
    {
        public class Function1
        {
            private readonly ILogger<Function1> _logger;
    
            public Function1(ILogger<Function1> logger)
            {
                _logger = logger;
            }
    
            [Function("TimerTrigger_EveryMinute")]
            public async Task TimerTrigger_EveryMinute(
            [TimerTrigger("0 * * * * *")] TimerInfo timerInfo,
            [DurableClient] DurableTaskClient starter)
            {
                _logger.LogError($"Running timer trigger");
    
                string instanceId = await starter.ScheduleNewOrchestrationInstanceAsync("MainOrchestrator", null);
                await starter.WaitForInstanceCompletionAsync(instanceId);
    
                _logger.LogError($"Completed timer trigger orchestration with ID = '{instanceId}'");
            }
    
            [Function("MainOrchestrator")]
            public async Task MainOrchestrator(
                [OrchestrationTrigger] TaskOrchestrationContext context)
            {
                _logger.LogError($"Running MainOrchestrator");
    
                var tasks = new List<Task>();
    
                tasks.Add(context.CallSubOrchestratorAsync("SubOrchestrator", null));
    
                await Task.WhenAll(tasks);
            }
    
            [Function("SubOrchestrator")]
            public async Task SubOrchestrator(
                [OrchestrationTrigger] TaskOrchestrationContext context, TransactionData transaction)
            {
                _logger.LogError($"Running SubOrchestrator");
            }
        }
        public class TransactionData
        {
            public string TransactionId { get; set; }
            public string TransactionType { get; set; }
        }
    }
    

    .csproj

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <AzureFunctionsVersion>v4</AzureFunctionsVersion>
        <OutputType>Exe</OutputType>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <RootNamespace>_78332074</RootNamespace>
      </PropertyGroup>
      <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.21.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.2.0-rc.1" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.2.1" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Timer" Version="4.3.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.3-preview1" />
        <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
        <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
      </ItemGroup>
      <ItemGroup>
        <None Update="host.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </None>
        <None Update="local.settings.json">
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
          <CopyToPublishDirectory>Never</CopyToPublishDirectory>
        </None>
      </ItemGroup>
      <ItemGroup>
        <Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
      </ItemGroup>
    </Project>
    

    I am getting below output.

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search