extensions: Hang when calling start/stop on IHost
The program below appears to hang after logging the application is shutting down message and I don’t understand why. The OnProcessExit event appears to be waiting here https://github.com/aspnet/Extensions/blob/master/src/Hosting/Hosting/src/Internal/ConsoleLifetime.cs#L79 but I don’t know why that would be or if that is a problem or just a red herring.
public class Program
{
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
await host.StartAsync();
await host.StopAsync();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices(services => services.AddHostedService<Worker>());
}
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 6
- Comments: 36 (17 by maintainers)
Commits related to this issue
- Add logging for the hanging case. Related to: #1363 — committed to maryamariyan/Extensions by maryamariyan 5 years ago
- Add logging for the hanging case. Related to: #1363 — committed to maryamariyan/Extensions by maryamariyan 5 years ago
- Add logging for the hanging case when calling start/stop #1363 (#2053) — committed to dotnet/extensions by maryamariyan 5 years ago
- Add logging for the hanging case when calling start/stop dotnet/Extensions#1363 (dotnet/Extensions#2053) Commit migrated from https://github.com/dotnet/Extensions/commit/2875a1ad56073d98cf0856fa726... — committed to maryamariyan/runtime by maryamariyan 5 years ago
- Add logging for the hanging case when calling start/stop dotnet/Extensions#1363 (dotnet/Extensions#2053) Commit migrated from https://github.com/dotnet/Extensions/commit/2875a1ad56073d98cf0856fa726... — committed to maryamariyan/runtime by maryamariyan 5 years ago
- Add logging for the hanging case when calling start/stop dotnet/Extensions#1363 (dotnet/Extensions#2053) Commit migrated from https://github.com/dotnet/Extensions/commit/2875a1ad56073d98cf0856fa726... — committed to maryamariyan/runtime by maryamariyan 5 years ago
- Add logging for the hanging case when calling start/stop dotnet/Extensions#1363 (dotnet/Extensions#2053) Commit migrated from https://github.com/dotnet/Extensions/commit/2875a1ad56073d98cf0856fa726... — committed to maryamariyan/runtime by maryamariyan 5 years ago
Yeah, we need to look at designing a real solution to this problem now.
It has nothing to do with background services. It’s all about the code in Program.cs that starts the host.
Timer log mitigation added. Backlog while working with CoreFx?
There is one more way to reproduce hanging or related weird behavior.
Environment.Exit()call in the main thread leads to permanent hang.Environment.Exit()in a background thread leads to hang forHostOptions.ShutdownTimeoutif you call it inBackgroundService(IHostedService.StopAsyncnever completes). Also if you use a non-zero error code with theEnvironment.Exit(), it will be replaced to zero in theConsoleLifetime.I think the best solution is to create a way to detect something like SIGTERM separately and have an option to prevent immediate app termination. Then
ConsoleLifetimecan handle this separate event just likeConsole.CancelKeyPressand do not useProcessExitevent at all.Is there some reason why the following code would not be an appropriate workaround for now. The code below does not hang and still runs your MyServiceA hosted service
I’m here to say that this was the cause of a test hang that led to lots o badness and sadness 😦
We know there are some corefx APIs needed to make this super clean and we’ll look in to that. The idea that shows the most promise is one that lets us actually just detect SIGTERM directly and tell corefx to cancel the default logic, handling it as a graceful shutdown instead. However, that’s not really feasible for 3.0 and it seems user-unfriendly to hang the application with no way of knowing why it’s hanging.
Until then, as a tactical fix to make this easier to understand, we’re going to propose this:
_shutdownBlockto be unblocked in OnProcessExit.WaitOne()returns false), immediately log a warningWaiting for the host to be disposed. Ensure all 'IHost' instances are wrapped in 'using' blocks.(or similar, we can wordsmith in the PR). The logger could throwObjectDisposedExceptionif we’re part-way through disposing though so we may need to be defensive._shutdownBlockafter logging that messageWhy not just exit after the timeout? The console log is buffered so we have no guarantee that it was actually written after logging.
Why not just exit immediately? That would bypass any dispose/shutdown logic in the app. At least this way a user has some chance of understanding why the app is hanging.
cc @Tratcher @halter73