Search code examples
c#.netasync-awaitnonblockingfire-and-forget

Fire and Forget multiple methods in C#


I have an Azure function which would have the ability to call multiple API endpoints without waiting for the results from any of them.

The Azure function runs on a timer trigger and runs every 10 seconds.

All my API calls and parameters to call them are stored in a SQL table. I want to make sure that the API calls are made without waiting for a particular call to be finished.

This is just a blueprint of what I'll be doing.

[FunctionName("FunctionScheduler")]
public static async Task RunAsync([TimerTrigger("*/10 * * * * *")]TimerInfo myTimer, ILogger log)
{
    log.LogInformation("FUNCTION SCHEDULER STARTING ..");

    log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");

    for(int i=0; i < 20; i++)
    {
        var task = Task.Run(() => ApiRef1(i, log));
        var taskref = await task;
    }

}

Currently ApiRef1() simply prints out the value of the variable i. I get the expected output of printing numbers 0 to 19. I want parallel executions of the ApiRef1() method which will eventually be replace by a method that looks like this.

private static void CallApi(string apiName, string apiEndpoint, string methodType, string authenticationType, IDictionary<int, string> parameters, ILogger log)
{
    try
    {
        log.LogInformation($"Call to API {apiName} started.." );

        // Call API
    }
    catch (Exception ex)
    {
        log.LogInformation($"Exception {ex.Message} occurred.." );
    }
}

Is there a better way to do this or will this method work?


Solution

  • As you're using an Azure function you cannot have true fire and forget as you risk the function terminating before the completion of all the task(s).

    However, we don't care for the result of the task, so we need not await each task individually.

    System.Collections.Generic.List<System.Threading.Tasks.Task> tasks = new System.Collections.Generic.List<System.Threading.Tasks.Task>();
    for (int i = 0; i < 20; i++)
    {
      tasks.Add(System.Threading.Tasks.Task.Run(() => ApiRef1(i, log));
    }
    await System.Threading.Tasks.Task.WhenAll(tasks);
    

    This allows all the tasks to fire in parallel, but pause further execution until they're all complete, ensuring the completion of the tasks before the process is terminated.