The Host initiated by WebApplicationFactory fails to terminate
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 281
Description
## Bug
The Host initiated by WebApplicationFactory fails to terminate.
## Reproduce:
### [Program.cs](https://github.com/t03apt/AppLifecycleTroubleshooting/blob/5f97b95396b819ba0a346ee147839a808729d584/WebApi/Program.cs)
```csharp
namespace WebApi;
public partial class Program
{
public static void Main(string[] args) => CreateHostBuilder(args).Build().Run();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup();
})
.ConfigureServices(services =>
{
services.Configure(options =>
{
options.ShutdownTimeout = TimeSpan.FromSeconds(1);
});
});
}
public class Startup
{
public static void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseEndpoints(endpoints => { endpoints.MapHealthChecks("/health"); });
}
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks();
services.AddHostedService();
}
}
public class MyBackgroundService(ILogger logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Yield();
try
{
while (!stoppingToken.IsCancellationRequested)
{
logger.LogInformation("My background service is running.");
await Task.Delay(1000, stoppingToken);
throw new InvalidOperationException();
}
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
// ignore
}
}
}
```
### [UnitTest1.cs](https://github.com/t03apt/AppLifecycleTroubleshooting/blob/5f97b95396b819ba0a346ee147839a808729d584/WebApiTests/UnitTest1.cs)
```csharp
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace WebApiTests
{
public class UnitTest1 : IClassFixture>
{
private readonly WebApplicationFactory _factory;
public UnitTest1(WebApplicationFactory factory)
{
_factory = factory;
}
[Fact]
public async Task ApplicationShouldShutdownGracefullyOnFailingHostedService()
{
// Arrange
var lifetime = _factory.Services.GetRequiredService();
// Act
await Task.Delay(TimeSpan.FromSeconds(5));
// Assert
Assert.True(lifetime.ApplicationStopping.IsCancellationRequested, "Expected lifetime.ApplicationStopping.IsCancellationRequested to be true");
Assert.True(lifetime.ApplicationStopped.IsCancellationRequested, "Expected lifetime.ApplicationStopped.IsCancellationRequested to be true");
}
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.