featured image

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 Yash Worlikar Tue Nov 12 2024 4 min read

In 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.

nowaitfor

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.

running_unhealty

While the RabbitMQ service hasn’t started yet, the web service will be waiting. 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. running

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.

waitfor

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.

efwait

Once the Postgres service becomes healthy, the migrationService project starts running, while the demowebapi project continues to wait.

demowait

After the migrationService project finishes its execution, the demowebapi project transitions to the running state and begins processing requests.

demostart

Here’s a flowchart that represents the above scenario.

flowchart

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

Prev
Should you use GPT-4o-mini for multimodal tasks?
Next
Improved function calling with the Semantic Kernel