How to cancel starting up a web application that is doing some initial startup logic (like seeding a DB)?
See original GitHub issueš Hi!
Iām trying to figure out how I can stop starting up my web application when Iām doing some initial application-startup logic, like seeding a database or loading some data from some URI/DB/etc into memory, etc.
The database seeding is an easy example, but it could be any ādependencyā that fails. And for this example, imagine that dependency is unavailable (e.g. DB is starting up because all these services start at the āsame timeā with docker-compose up).
In the public void Configure(..) method (in startup.cs) this is a great place to start DB seeding.
So what I do is:
- Seed data.
- if error, retry.
- repeat for 15 times ⦠which takes a total of about 30 seconds max.
- else ⦠crash/exception if 15 attempts all failed.
The āretryā action is using Polly.
In the middle of the Polly retries I hit CTRL-C and the application says āstoppingā ⦠but Polly doesnāt know about this and keeps retrying.
I thought the trick was to pass the applicationLifetime.ApplicationStopping CancellationToken down to the logic which calls/retries. Doing this, the token is always false (ie. nothing to cancel ⦠keep on trucking).
I tried asking this in the Polly repo but weāre also stuck ⦠because we feel like this is more related to the underlying framework or more specifically, what Iām not coding correctly.
So lets look at some code and some pwitty picturesā¦
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
IDocumentStore documentStore,
IOptions<CorsSettings> corsSettings,
IApplicationLifetime applicationLifetime, // <-- TAKE NOTE
ILogger<Startup> logger)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseProblemDetails()
.UseCustomCors(corsSettings.Value)
// OK -> here we go. lets 'UseRavenDb' which will seed some data.
.UseRavenDb(env.IsDevelopment(),
documentStore,
applicationLifetime.ApplicationStopping,
logger)
.UseAuthentication()
.UseCustomSwagger("accounts", SwaggerTitle)
.UseMvc();
}
So first up, lets seed some data to the DB (in this case RavenDB) and pass along the ApplicationStopping token from an IApplicationLifetime which was injected in.
this eventually calls this check to see if the database exists, before i throw data into it ā¦
DatabaseStatistics existingDatabaseStatistics = null;
try
{
var checkRavenDbPolicy = CheckRavenDbPolicy(cancellationToken, logger);
checkRavenDbPolicy.Execute(token =>
{
existingDatabaseStatistics = documentStore.Maintenance.Send(new GetStatisticsOperation());
}, cancellationToken);
}
... <snipped the catches>
The policy is a retry 15x with a 2 second delay between retries. Simple. (oldish code in the image below.)
And this is what it looks like when I hit CTRL-C in the middle of the retryās because I didnāt start the DB (on purpose) :
Ok ⦠application is shutting downā¦
Ok - so weāve paused inside when an exception is thrown and the policy is handling it. Lets check out what the cancellationToken is ā¦
and it looks like the cancellationToken is saying ānothing to handle. nothing cancelled. keep on cruisingā.
So Iām not sure how to leverage the applicationLifetime.ApplicationStopping property, correctly. Or if thatās the correct property to leverage.
Issue Analytics
- State:
- Created 4 years ago
- Comments:29 (27 by maintainers)

Top Related StackOverflow Question
I disagree. The
Configuremethod is a place to set up the application but not to establish pre-conditions about the application. It is further executed by other tools, likedotnet efor theWebApplicationFactory, which makes it sub-optimal for preparing stuff for actually launching the application.My usual recommendation is to seed the database outside of the
Startupat the host or web host level. By doing that, you are seeding before you actually start the application which also gives you the benefit of not serving the application early although it is not yet ready.So by following this approach, you have a lot more control about when the application is actually started and you can use that to properly seed your database first and only start the application once that is successfully completed. And since you are now outside of complex lifetimes, you can also control cancelling a lot easier.
In general, this would look something like this:
And since this runs now as a normal console application without anything magic, you can also simply check for the
Console.CancelKeyPressto check for Ctrl+K and pass that on to a cancellation token for example that then interrupts your seed process.Thank you to everyone participating in this issue and discussion. Lots of respect to you all š°