Home > front end >  Executing async code after startup, once API is up for requests
Executing async code after startup, once API is up for requests

Time:10-25

I'm trying to execute logic on start up of my web API and this code will also be async.

I've thought of IStartupFilter but this is sync, which is a problem. StartUp.Configure() is also not an option, sync.

I've thought of IHostedService but this runs before the application is done loading and up for requests.

Any other ways of doing this ?

CodePudding user response:

Something you probably didn't realize is that running the application has 2 parts, that are hidden by default when you call IHost.Run/IHost.RunAsync.

Basically, this:

var host = CreateHostBuilder(args).Build();
await host.RunAsync();

Is equivalent to this:

var host = CreateHostBuilder(args).Build();

await host.StartAsync();
await host.WaitForShutdownAsync();

When StartAsync returns, the application has already started and is ready to consume requests, so you probably want to do this:

var host = CreateHostBuilder(args).Build();

await host.StartAsync();

await PerformSomeWorkAfterStartupAsync();

await host.WaitForShutdownAsync();

CodePudding user response:

Implement IStartupTask, register StartupTaskRunner and YourStartupTask in DI:

services    
    .AddStartupTasksRunner()
    .AddStartupTask<YourStartupTask>();

And here the code based on Andrew's Lock post:

public interface IAsyncStartupTask
{
    Task OnStartupAsync();
}
internal class StartupTasksRunner : IHostedService
{
    private readonly ILogger<StartupTasksRunner> _logger;
    private readonly IEnumerable<IAsyncStartupTask> _startupTasks;

    public StartupTasksRunner(ILogger<StartupTasksRunner> logger, IEnumerable<IAsyncStartupTask> startupTasks)
    {
        _logger = logger;
        _startupTasks = startupTasks;
    }
    public async Task StartAsync(CancellationToken cancellationToken)
    {
        foreach (var task in _startupTasks)
        {
            var stopwatch = Stopwatch.StartNew();

            try
            {
                await task.OnStartupAsync().ConfigureAwait(false);
            }
            catch (Exception e)
            {
                var seconds = stopwatch.Elapsed.TotalSeconds;
                _logger.LogError(e, $"Startup task '{task.GetType().Name}' failed after {seconds:0.###} sec");
                throw;
            }
            finally
            {
                var seconds = stopwatch.Elapsed.TotalSeconds;
                _logger.LogInformation($"Startup task '{task.GetType().Name}' execution time: {seconds:0.###} sec");
            }
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}
public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddStartupTasksRunner(this IServiceCollection services)
    {
        return services.AddHostedService<StartupTasksRunner>();
    }

    public static IServiceCollection AddStartupTask<TStartupTask>(this IServiceCollection services)
        where TStartupTask : class, IAsyncStartupTask
    {
        return services.AddSingleton<IAsyncStartupTask, TStartupTask>();
    }
}
  • Related