0

I have a basic Azure function that starts with a timmer (1 min for testing), but after hours of trying to make it work, I can't get my data from the firestore.

The trigger:

[FunctionName("OrchestrationTriggerFunction")]
public async static Task OrchestrationTriggerFunction(
        [TimerTrigger("0 */1 * * * *")] TimerInfo myTimer,
        [DurableClient] IDurableOrchestrationClient starter)
{
  await starter.StartNewAsync("Function1", null);
}

Function1:

[FunctionName("Function1")]
public async Task Function1(
  [OrchestrationTrigger] IDurableOrchestrationContext context
  )
{
  List<string> OrgsToProcess = new List<string>() { "ID" };

  foreach (string org in OrgsToProcess)
  {

    var vehicles = await context.CallActivityAsync<List<Vehicle>>("GetFirestoreVehicles", org);    

    var parallelTasks = new List<Task<Result>>();

    foreach (var vehicle in vehicles)
    {
      // processing code

      Task<CsvResult> task = context.CallActivityAsync<Result>("ProcessData", msg);
      parallelTasks.Add(task);
    }
    await Task.WhenAll(parallelTasks);

    await context.CallActivityAsync("Function2", parallelTasks);
    return;
  }
}

GetFirestoreVehicles:

[FunctionName("GetFirestoreVehicles")]
public Task<List<Vehicle>> GetFirestoreVehicles([ActivityTrigger] string org)
{
  return _firestoreDb.GetVehicles(org);
}

In Function1, on var vehicles = await context.CallActivityAsync<List<Vehicle>>("GetFirestoreVehicles", org); I can see that it has the correct number of records, however all the properties are filled with null.

When looking at the GetFirestoreVehicles during the debugging it says Result = "{Not yet computed}" and I'm unable to use await in my firestore method as it throws the following exception: multithreaded execution was detected. This can happen if the orchestrator function code awaits on a task that was not created by a DurableOrchestrationContext method

How can I make my Durable Function await the data from firestore?

João Silva
  • 531
  • 4
  • 21
  • 40

1 Answers1

2

The GetFirestoreVehicles function should await the result to function properly like this:

[FunctionName("GetFirestoreVehicles")]
public async Task<List<Vehicle>> GetFirestoreVehicles([ActivityTrigger] string org)
{
    return await _firestoreDb.GetVehicles(org);
}

Also, this line is very strange:

await context.CallActivityAsync("Function2", parallelTasks);

You are passing a list of Task<T> to another function. Instead, you need to pass the resulting list of T, not the Task collection itself. Something like this will do:

var results = parallelTasks.Select(t => t.Result);  
await context.CallActivityAsync("Function2", results);

That means Function2 should accept IEnumerable<Result> instead of List<Task<Result>>

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Peter Bons
  • 26,826
  • 4
  • 50
  • 74
  • Good spot on the last line, regarding the firestore, the await still does not work in there, if I replace the line in Function1 `var vehicles = await context.CallActivityAsync>("GetFirestoreVehicles", org);` with the firestore call directly, I'm able to get the vehicles data but then I get the `multithreaded execution was detected.` exception – João Silva Mar 15 '23 at 13:21
  • @JoãoSilva you mean that inside the foreech you put `var vehicles = await _firestoreDb.GetVehicles(org);` instead of `var vehicles = await context.CallActivityAsync>("GetFirestoreVehicles", org);` and it still did not work? – Peter Bons Mar 15 '23 at 13:51
  • If I do that it works in getting the vehicles, however when it reaches the `await Task.WhenAll(parallelTasks);` it throws an exception because of the multi threading (more info: https://stackoverflow.com/a/49478697/2486919) I think I'm close to a solution, it's weird but returning a list of strings instead of the objects worked, so right now I created a new firestore method that serialize each vehicle to string and then in my `Function1` I'm deserializing them. I'm doing a few more tests and if it works I'll just mark this answer as the solution – João Silva Mar 15 '23 at 13:56