I have an Orchestrator function as follows
[FunctionName("ExportOrchestratorFunction")]
public async Task RunOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context)
{
var processId = context.InstanceId;
var custNo = _configuration.GetValue<string>("CustNo");
var roads = await context.CallActivityAsync<IEnumerable<RoadReport>>("GetCustomersByRoadFunction", new RoadCustomerRetrievalParameters
{
CustNo = custNo ?? "*",
Road = RoadName ?? "*",
ActiveFlag = "*",
APIFlag = "*",
ProcessId = processId
});
var roadReports = string.Join(',', roads.Select(r => r.Road).ToArray());
_logger.LogInformation($"Retrieved roads with customers count: { roadReports }. Process ID: {processId}");
var tasks = new List<Task<RoadExportData>>();
// Fan -out
foreach (var road in roads)
{
_logger.LogInformation($"Creating retrieval task for {road.Road}. Process ID: {processId}");
var task = context.CallActivityAsync<RoadExportData>(
"RoadRetrievalFunction",
new RoadRetrievalParameters
{
Road = road.Road,
ProcessId = processId,
CustNos = road.Customers
}
);
tasks.Add(task);
}
_logger.LogInformation($"Starting all tasks to retrieve Data. Process ID: {processId}");
// Fan -in: Wait for all tasks to complete
var exportResults = await Task.WhenAll(tasks);
// Aggregate the results
var allExportData = exportResults.ToList();
_logger.LogInformation($"All ETA retrieved { allExportData }");
await context.CallActivityAsync<int>("LogAndPersistFunction", new PersistDataParameters
{
ExportData = allExportData,
ProcessId = processId
});
}
When I ran this Orchestrator in the Azure environment I noticed the logs of one activity function logged more than once. What is the reason for this? How can we make sure that the activity functions run once except the fanned out functions?
An activity can be run again if something goes wrong internally in Durable Functions. Generally your activities should be idempotent, i.e. they should have the same effect if running again.
One thing I notice in your orchestrator is that you are getting a config value on each replay:
var custNo = _configuration.GetValue<string>("CustNo");
This violates the determinism principle of orchestrators. You should move this value to be an input for the orchestrator. So when you start the orchestrator, get this value and send it as an input. This way the value can never change during the run.
3