question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Eternal orchestration eventually stops calling activity functions

See original GitHub issue

Description I have a durable function using the singleton pattern to ensure only one instance of it ever runs. I’ve created a simplified version below that calls an activity function to simulate some work and then waits for an external event. Once the external event arrives it uses ContinueAsNew to start over again.

The reason I’m using the external event is because the trigger that starts the orchestrator can fire at any moment and so if the orchestrator is already running I’ll want it to start all over again as soon as it has completed its current run.

This seems to run perfectly, however, at some point in time the orchestrator just stops calling any activities. I know this is incredibly vague, but I can’t find any pattern or reason as to why this happens. Checking the logs I see a log to say that the trigger function is sending the wake event to the orchestrator, then I see “Executing orchestrator” and then “Executed orchestrator”. I see no logs to say it has run the activitiy.

The thing is, it must be running it because it still responds for the external event every time the trigger function sends it, it just doesn’t run the activity.

namespace GJTest.Function
{
    public static class DurableFunctionsOrchestrationCSharp1
    {
        const string _instanceId = "some-unique-instance-id";

        const string _eventIdentifier = "NewEvents";

        [FunctionName(nameof(RunOrchestrator))]
        public static async Task RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log)
        {
            await context.CallActivityAsync(nameof(SimulateWork), null);

            await context.WaitForExternalEvent(_eventIdentifier);
            context.ContinueAsNew(null);
        }

        [FunctionName(nameof(SimulateWork))]
        public static async Task SimulateWork([ActivityTrigger] IDurableActivityContext context, ILogger log)
        {
            log.LogInformation("Simulating some work");
            await Task.Delay(TimeSpan.FromSeconds(5));
            log.LogInformation("Finished simulating some work");
        }

        [FunctionName("HttpTriggerOrchestrator")]
        public static async Task<HttpResponseMessage> HttpStart(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req,
            [DurableClient] IDurableOrchestrationClient starter,
            ILogger log)
        {
            if (await OrchestrationHasFinished(starter, log))
            {
                log.LogInformation("Starting a new instance of orchestration");
                await starter.StartNewAsync(nameof(RunOrchestrator), _instanceId);
            }
            else
            {
                log.LogInformation("Orchestrator already running, sending wake event");
                await starter.RaiseEventAsync(_instanceId, _eventIdentifier);
            }

            return starter.CreateCheckStatusResponse(req, _instanceId);
        }

        private static async Task<bool> OrchestrationHasFinished(IDurableOrchestrationClient starter, ILogger log)
        {
            var existingInstance = await starter.GetStatusAsync(_instanceId);
            log.LogInformation($"Orchestration status is {existingInstance?.RuntimeStatus.ToString()}");

            return existingInstance == null 
                || existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Completed 
                || existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Failed 
                || existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Terminated;
        }
    }
}

Expected behavior Orchestrator runs forever and starts over after receiving the external event.

Actual behavior At some unspecified point the function eventually stops calling the activity functions. Or at least that is what appears to be happening.

To get it working again, I have to terminate the orchestration and use a new instance ID. I imagine I’d achieve the same results by deleting the instance from the instances table.

App Details Microsoft.Azure.WebJobs.Extensions.DurableTask: v2.9.2 Azure Functions runtime version: 4 Programming language used: dotnet

I should add that I’ve recently updated to the latest (v2.9.5) of the DurableTask package so I’m currently monitoring it with that version.

Issue Analytics

  • State:closed
  • Created 4 months ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
grantjamescommented, Jun 5, 2023

Thanks for your response, @nytiannn! Yes, you’re correct in that I don’t see any TaskScheduled/TaskCompleted events in the logs.

I’ll continue to monitor the function and will check the work item queue if I experience the same behaviour again.

0reactions
grantjamescommented, Jun 27, 2023

Thank you very much, @nytiannn 😃 I really appreciate your help. I think my problem definitely lies in an activity function causing issues and not the durable functions library. I’m happy for this issue to be closed.

Thanks again.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Eternal orchestrations stopped randomly · Issue #529
I start to see my eternal orchestration code is stopped randomly without known issue, it supposed to keep running forever every 5 minutes....
Read more >
Eternal orchestrations in Durable Functions - Azure
If an orchestrator function needs to eventually complete, then all you need to do is not call ContinueAsNew and let the function exit....
Read more >
Durable Functions - Activities seem to stop
If those 400 activities take longer than 10 minutes in total to process, it seems that it doesn't complete, and doesn't pick up/continue...
Read more >
Durable Functions #2: Eternal orchestrations & external events
This is the second part of the Durable Functions series. In this video I'll talk about eternal function orchestrations and external events.
Read more >
Containerized Activities in Durable Workflows - Part 5
A HTTP triggered starter function starts off a new Durable Functions orchestration; The orchestrator function calls an activity function ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found