This document provides examples and documentation on Azure Durable Functions patterns and concepts. It includes examples of orchestrator and activity functions, orchestration triggers, and common patterns like function chaining, fan-out/fan-in, and asynchronous HTTP responses. It also covers durable function concepts such as the control queue, work item queue, and history table.
5. “Hello Seoul!”[“Hello Seoul!”]
Orchestrator
Function
Activity
Function
Execution
History
var outputs = new List<string>();
outputs.Add(await context.CallActivityAsync<string>("SayHello", “Seoul"));
return outputs;
Orchestrator
Function
?
Activity
Function
“Hello Seoul!”
Orchestrator Started
Execution Started
Task Scheduled, SayHello, “Seoul”
Orchestrator Completed
Task Completed, “Hello Seoul!”
Orchestrator Started
Execution Completed, ["Hello Seoul!"]
Orchestrator Completed
6.
7. [FunctionName(nameof(ActivityFn))]
public static string ActivityFn(
[ActivityTrigger] DurableActivityContext context, ILogger log)
{
string name = context.GetInput<string>();
string instanceId = context.InstanceId;
log.LogInformation($"[{instanceId}] Saying hello to {name}.");
return $"Hello {name}!";
}
{
"name": "<Name of input parameter in function signature>",
"activity": "<Optional - name of the activity>",
"type": "activityTrigger",
"direction": "in"
}
8.
9. [FunctionName(nameof(OrchestratorFn))]
public static async Task<List<string>> OrchestratorFn(
[OrchestrationTrigger] DurableOrchestrationContext context)
{
var outputs = new List<string>();
outputs.Add(await context.CallActivityAsync<string>(nameof(ActivityFn), "Seoul"));
outputs.Add(await context.CallActivityAsync<string>(nameof(ActivityFn), "Busan"));
outputs.Add(await context.CallActivityAsync<string>(nameof(ActivityFn), "Incheon"));
return outputs;
}
{
"name": "<Name of input parameter in function signature>",
"orchestration": "<Optional - name of the orchestration>",
"type": "orchestrationTrigger",
"direction": "in"
}
10.
11. [FunctionName(nameof(ClientFn))]
public static async Task<HttpResponseMessage> ClientFn(
[HttpTrigger(AuthorizationLevel.Anonymous, "get")]HttpRequestMessage req,
[OrchestrationClient]DurableOrchestrationClient starter,
ILogger log)
{
string instanceId = await starter.StartNewAsync(nameof(OrchestratorFn), null);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
return starter.CreateCheckStatusResponse(req, instanceId);
}
{
"name": "<Name of input parameter in function signature>",
"taskHub": "<Optional - name of the task hub>",
"connectionName": "<Optional - name of the connection string app setting>",
"type": "orchestrationClient",
"direction": "in"
}
12. public class DurableOrchestrationClient : DurableOrchestrationClientBase
{
… Task<string> StartNewAsync(…);
… Task TerminateAsync(…);
… Task<IList<DurableOrchestrationStatus>> GetStatusAsync(…);
… Task TerminateAsync(…);
… HttpResponseMessage CreateCheckStatusResponse(…);
}
public class DurableOrchestrationStatus
{
public string Name { get; }
public string InstanceId { get; }
public DateTime CreatedTime { get; }
public DateTime LastUpdatedTime { get; }
public JToken Input { get; }
public JToken Output { get; }
public OrchestrationRuntimeStatus RuntimeStatus { get; }
public JToken CustomStatus { get; }
public JArray History { get; }
}
13.
14. Pattern #1: Function Chaining
F1 F2 F3 F4
// calls functions in sequence
public static async Task<object> Run(DurableOrchestrationContext ctx)
{
try
{
var x = await ctx.CallFunctionAsync("F1");
var y = await ctx.CallFunctionAsync("F2", x);
var z = await ctx.CallFunctionAsync("F3", y);
return await ctx.CallFunctionAsync("F4", z);
}
catch (Exception)
{
// global error handling/compensation goes here
}
}
16. public static async Task Run(DurableOrchestrationContext ctx)
{
var parallelTasks = new List<Task<int>>();
// get a list of N work items to process in parallel
object[] workBatch = await ctx.CallActivityAsync<object[]>("F1");
for (int i = 0; i < workBatch.Length; i++)
{
Task<int> task = ctx.CallActivityAsync<int>("F2", workBatch[i]);
parallelTasks.Add(task);
}
await Task.WhenAll(parallelTasks);
// aggregate all N outputs and send result to F3
int sum = parallelTasks.Sum(t => t.Result);
await ctx.CallActivityAsync("F3", sum);
}