Using the Waitfor and WaitforCompletion in .NET Aspire 9
Learn how to use the new WaitFor and WaitForCompletion methods in .NET Aspire 9 to manage dependencies in your distributed applications.
Yash Worlikar Tue Nov 12 2024 4 min readIn a distributed system, resources often depend on each other. For instance, a web service might depend on a database being fully initialized before it can start. Managing these dependencies locally can be time-consuming and error-prone.
The newly introduced WaitFor()
and WaitForCompletion()
methods in .NET Aspire 9 make it easier to manage these local resource dependencies. These methods ensure that resources wait for their dependencies to be ready before starting, which helps prevent startup failures, ensuring that resources are healthy before they are used.
Do note that these methods are currently in rc1 release and may change before the final release
WaitFor Method
The WaitFor
method ensures that a resource waits for its dependency to enter the Running state before it starts. This is particularly useful in scenarios where the dependent resource must be fully operational before the resource can be accessed.
Let’s say our .NET app depends on the RabbitMQ messaging services. Here’s how we will define it in our app host project.
var builder = DistributedApplication.CreateBuilder(args);
var messaging = builder.AddRabbitMQ("messaging");
builder.AddProject<Projects.MyApp>("demowebapi")
.WithReference(messaging)
Without the WaitFor
even if the RabbitMQ service failed to start for some reason, the .NET app wouldn’t show any error on the dashboard.
Now let’s Add the WaitFor
method to our demo project.
var builder = DistributedApplication.CreateBuilder(args);
var messaging = builder.AddRabbitMQ("messaging");
builder.AddProject<Projects.MyApp>("demowebapi")
.WithReference(messaging)
.WaitFor(messaging);
Here we are waiting for the RabbitMQ
container to start successfully before starting the demowebapi
project.
In the earlier scenario, even when the RabbitMQ service failed to start, the web service continued to run. However, by using the WaitFor
method, the web service will be prevented from starting until the RabbitMQ service is successfully running(in a healthy state). This guarantees that the web service only starts once its dependencies are fully operational.
While the RabbitMQ service hasn’t started yet, the web service will be waiting.
Only after the RabbitMQ service starts successfully and is ready to accept requests, the web service will move to the running state and start serving requests.
If for some reason the RabbitMQ service fails to start (for example, because the Docker image is not available), the web service will also fail to start.
WaitForCompletion Method
The WaitForCompletion method ensures that a resource waits for its dependency to finish (entering the Exited or Finished state) before it begins. This is particularly useful in scenarios like database initialization, where the dependency must complete its setup before the dependent resource can proceed. Let’s look at an example:
Say we have a PostgreSQL database and a project that applies database migrations and our demo API project.
var builder = DistributedApplication.CreateBuilder(args);
// Add PostgreSQL service
var pgsql = builder.AddPostgres("postgres");
// Add a Worker service proj that runs ef migrations and waits for pgsql
var migrationService = builder.AddProject<Projects.EfMigrationService>("efmigrationservice")
.WithReference(pgsql)
.WaitFor(pgsql);
// Add and configure the MyApp project that waits for pgsql to be healthy and migrationService to complete (Finished status)
builder.AddProject<Projects.MyApp>("demowebapi")
.WithReference(pgsql)
.WaitFor(pgsql)
.WaitForCompletion(migrationService);
Here the migrationservice project waits for the Postgres service to be healthy before starting. And then the demowebapi
project waits for the Postgres service to be running and the migrationservice project to be in a finished state before starting.
Initially, both the migrationService
and demowebapi
projects remain in a waiting state as the Postgres service is initializing.
Once the Postgres service becomes healthy, the migrationService
project starts running, while the demowebapi
project continues to wait.
After the migrationService
project finishes its execution, the demowebapi
project transitions to the running state and begins processing requests.
Here’s a flowchart that represents the above scenario.
Conclusion
The WaitFor
and WaitForCompletion
methods in .NET Aspire 9 are a powerful way to manage dependencies when developing locally. By using these methods, you can ensure that your resources start and run in the correct order, based on the dependencies you define. This makes it easier to manage complex distributed systems and ensures that your applications are more robust and resilient.
For all the new features introduced in .NET Aspire 9 check out the official post https://learn.microsoft.com/en-us/dotnet/aspire/whats-new/dotnet-aspire-9-release-candidate-1