If you need to define a workflow that scales, by having multiple functions running in parallel the Fan out/fan in Pattern is the application pattern to use with Durable Functions.
This is a series where I am explaining the components of durable functions1 and the different application patterns of implementation.
The Fan out/fan in pattern allows the processing of activities in parallel, which means multiple functions are spun to execute the activities, and at the end of processing the orchestrator waits for all parallel activities to finish. In this example, we get multiple Orders for Processing, and at the end, we send a notification. They are represented by the following activities: GetOrders, ProcessOrder and SendNotification.
The FanOutIn_HttpStart is the HTTP Trigger.
Starter Function (aka DurableClient)
1
2
3
4
5
6
7
8
9
10
11
12
[FunctionName($"{nameof(FanOutIn)}_HttpStart")]publicasyncTask<HttpResponseMessage>HttpStart([HttpTrigger(AuthorizationLevel.Anonymous,"get","post")]HttpRequestMessagereq,[DurableClient]IDurableOrchestrationClientstarter,ILoggerlog){varinstanceId=awaitstarter.StartNewAsync(nameof(Orchestrator));log.LogInformation($"Started orchestration with ID = '{instanceId}'.");returnstarter.CreateCheckStatusResponse(req,instanceId);}
This is an HTTPTrigger function that can be triggered from this CURL request:
The Orchestrator controls all the activities. It loads Orders from GetOrders and then it processes the Orders by calling multiple ProcessOrder activities in a foreach loop.
In the end, it retrieves all orderNumbers and calls the activity SendNotification to finalize the orchestrator.
Check the PlayGoKids repository for details of IOrderService.
[FunctionName(nameof(Orchestrator))]publicasyncTaskRunOrchestrator([OrchestrationTrigger]IDurableOrchestrationContextcontext){varorderProcessingTasks=newList<Task<string>>();// Get a list of orders
varorders=awaitcontext.CallActivityAsync<List<Order>>(nameof(IOrderService.GetOrders),DateTime.Now);foreach(varorderinorders){// Process orders in parallel
Task<string>task=context.CallActivityAsync<string>(nameof(IOrderService.ProcessOrder),order);orderProcessingTasks.Add(task);}// Wait for all orders to process
varorderNumbers=awaitTask.WhenAll(orderProcessingTasks);// Send notification
awaitcontext.CallActivityAsync(nameof(IOrderService.SendNotification),orderNumbers);}
Activity Functions
The activities were created in order Top-down, displayed below:
publicclassActivity{privatereadonlyIOrderService_orderService;publicActivity(IOrderServiceorderService){_orderService=orderService;}[FunctionName(nameof(IOrderService.GetOrders))]publicList<Order>GetOrders([ActivityTrigger]DateTimedateTime,ILoggerlog){log.LogInformation($"Getting orders.");varorders=_orderService.GetOrders(dateTime);returnorders;}[FunctionName(nameof(IOrderService.ProcessOrder))]publicstringProcessOrder([ActivityTrigger]Orderorder,ILoggerlog){log.LogInformation($"Processing order {order.OrderNumber}");varorderNumber=_orderService.ProcessOrder(order);returnorderNumber;}[FunctionName(nameof(IOrderService.SendNotification))]publicvoidSendNotification([ActivityTrigger]string[]orderNumbers,ILoggerlog){log.LogInformation($"Send notification.");_orderService.SendNotification(orderNumbers);}}
The OrderService is just a dummy that implements the Activity actions. It doesn’t do much:
publicclassOrderService:IOrderService{publicList<Order>GetOrders(DateTimedateTime){//TODO: Retrieve orders for a particular date
returnnewList<Order>(){newOrder(){OrderNumber="ON-00001"},newOrder(){OrderNumber="ON-00002"},newOrder(){OrderNumber="ON-00003"},newOrder(){OrderNumber="ON-00004"},newOrder(){OrderNumber="ON-00005"}};}publicstringProcessOrder(Orderorder){//TODO: Any processing
returnorder.OrderNumber;}publicvoidSendNotification(string[]orderNumbers){//TODO: Send notification
}}
This is an example of how to use the Fan out/fan in pattern, applied to the processing of Orders.
In the next article of the series let’s check out how to use the async HTTP API pattern.
Join the conversation! Share your thoughts and connect with other readers.