StartAsync asynchronously starts a configured application or host and completes when startup processing finishes. In an IHostedService, it runs inline during application startup, so awaiting lengthy work delays request handling. section 34.1.1 section 36.3.1
Use StartAsync with these behaviors in mind:
- Return a task immediately when starting long-running background work; schedule the work elsewhere instead of awaiting it inside StartAsync. section 34.1.1
- Await startup work deliberately when the application must not handle requests until initialization succeeds. section 34.1.1
- Prefer BackgroundService and ExecuteAsync for recurring work that runs for the application lifetime. section 34.1.1
Blocking startup until an update succeeds
An IHostedService can override StartAsync, retry an initial update while cancellation has not been requested, and then call the base implementation. This keeps the host from starting until the required initialization completes. section 34.1.1
Listing 34.4 Implementing StartAsync to block startup in an IHostedService
public class ExchangeRatesHostedService : BackgroundService
{
private readonly IServiceProvider _provider;
private readonly ExchangeRatesCache _cache;
public ExchangeRatesHostedService(
IServiceProvider provider, ExchangeRatesCache cache)
{
_provider = provider;
_cache = cache;
}
public override async Task StartAsync( #1
CancellationToken cancellationToken) #1
{
var success = false;
while(!success && !cancellationToken.IsCancellationRequested) #2
{ #2
success = await TryUpdateRatesAsync(); #2
} #2
await base.StartAsync(cancellationToken); #3
}
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
await TryUpdateRatesAsync();
}
}
private async Task<bool> TryUpdateRatesAsync()
{
try
{
var client = _provider
.GetRequiredService<ExchangeRatesClient>();
string rates = await client.GetLatestRatesAsync();
_cache.SetRates(rates);
return true;
}
catch(Exception ex)
{
return false;
}
}
}
#1 The StartAsync method runs on start, before the app starts handling requests.
#2 Keeps trying to update the rates until it succeeds
#3 Once the update succeeds, starts the background process
Inspect the StartAsync implementation that retries an exchange-rate update before allowing the host to finish starting. section 34.1.1
