In the blog post about endless running Azure Functions on Consumption Plan, normal Azure Functions can run without time limit with the help of the functionTimeout property. The same option is also available for the durable functions. The same timeout restrictions apply here on the consumption plan (default 5 minutes, maximum 10 minutes).

Function Runtime ~3

In the Azure Runtime ~3, the unlimited runtime can be defined by configuring the host.json file. You can see the configuration in the previous post.

As a result, the entire functional sequence can take place in the activity function without any real orchestration having to take place. As a rule, it does not make sense to use a durable function and perform the entire calculation in a single activity call:

        public static string Consumer([ActivityTrigger] ConsumerParameter cParams, ILogger log)
        {
            log.LogInformation($"DurableTimeconsumingCalculation_Consumer statring with runs={cParams.runs} and value={cParams.value}...");
            for(int i=0; i<cParams.runs; i++){
                var res = ConsumeCPU(cParams.value);//.GetAwaiter().GetResult();
                log.LogInformation($"DurableTimeconsumingCalculation_Consumer Func has run at round {i+1} with result {res} ({System.DateTime.UtcNow.ToLongTimeString()})");
            }
            var msg = $"finished after {cParams.runs} runs!";
            log.LogInformation(msg);
            return msg;
        }

Function Runtime ~4

The procedure for Function Runtime ~3 can no longer be used for Function Runtime ~4. Because the timeout for RT ~4 can only be defined to a maximum of 10 minutes. This means that the calculation must be carried out by the orchestration. In this example, the calculation was implemented using function chaining patterns, i.e. the runs are coordinated in the orchestration function and the individual calculations are carried out in the activity function:

        [FunctionName("DurableTimeconsumingCalculation")]
        public static async Task<List<string>> RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log)
        {
            var outputs = new List<string>();
            ConsumerParameter cParams = context.GetInput<ConsumerParameter>();
            log.LogInformation($"DurableTimeconsumingCalculation statring with runs={cParams.runs} and value={cParams.value}...");

            for(int i=0; i<cParams.runs; i++){
                ConsumerParameter tmpParam = new ConsumerParameter() { runs = i, value = cParams.value };
                outputs.Add(await context.CallActivityAsync<string>("DurableTimeconsumingCalculation_Consumer", tmpParam));
            }
            
            return outputs;
        }

        [FunctionName("DurableTimeconsumingCalculation_Consumer")]
        public static string Consumer([ActivityTrigger] ConsumerParameter tmpParam, ILogger log)
        {
            var res = ConsumeCPU(tmpParam.value);//.GetAwaiter().GetResult();
            log.LogInformation($"DurableTimeconsumingCalculation_Consumer Func has run at round {tmpParam.runs} with result {res} ({System.DateTime.UtcNow.ToLongTimeString()})");
            var msg = $"Consumer finished run {tmpParam.runs} with {res}";
            log.LogInformation(msg);
            return msg;
        }

The timeout value of a maximum of 10 minutes applies to all 3 functions, to the caller/trigger function as well as the orchestration function and the activity functions must be subordinate to this restriction. This means that the activity calculation can not exceed the maximum timeout.


Sourcecode on Github on the folders DurableFunction-RT3 and DurableFunction-RT4