使用异步线程的退出代码退出应用程序
Exit the application with exit code from async thread
我的 .NET5 Web API 项目(除了 REST)监听 Telegram 消息。目标很简单:
- 当用户发送 exit 消息时 - 使用退出代码 8
终止应用程序
- 当消息处理程序抛出 SeriousException - 使用退出代码 8 终止应用程序
不幸的是,由于消息轮询的异步特性,我正在努力实现这个目标。我在 GitHub 中准备了一个示例项目:https://github.com/chris-rutkowski/AsExPoC .
我在 Stack Overflow 上发现了许多类似的主题,但对我来说没有什么真正有用,而且大量建议的解决方案(一些 AsyncHelpers 等)似乎有点过分。我正在考虑将 Thread.CurrentThread
传递给服务并以某种方式在其上抛出异常,但我不知道如何,或者它是否可能发生,即使可能发生,这是否是最佳实践。我对 C#+.NET 了解不多,但在 Swift (iOS) 中,我会很容易地解决它,只需 3 行包括大括号:
DispatchQueue.main.async {
throw ForcedExitException()
}
这是我精简的 .NET5 Web Api,您可以在 repo.
中找到
Program.cs
public class Program
{
public static int Main(string[] args)
{
try
{
var host = CreateHostBuilder(args).Build();
var service = host.Services.GetRequiredService<DummyService>();
service.Run();
// other services are running too - I cannot just wait for DummyService to throw the exception
host.Run();
return 0;
}
catch (ForcedExitException)
{
return 8;
}
catch (Exception ex)
{
return 1;
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
DummyService.cs
public class DummyService
{
private readonly DummyMessenger _dummyMessenger;
public DummyService()
{
_dummyMessenger = new DummyMessenger();
}
public async void Run()
{
_dummyMessenger.StartReceiving();
_dummyMessenger.Add(async (_, message) => {
Console.WriteLine($"received message {message}");
await Task.Delay(50);
if (message == "exit")
throw new ForcedExitException();
});
}
}
我的期望:
Exited with error code 8
这是我在控制台中看到的:
Exited with error code 134, with the following stacktrace
Unhandled exception. AsExPoC.ForcedExitException: Exception of type 'AsExPoC.ForcedExitException' was thrown.
at AsExPoC.DummyService.<>c.<Run>b__2_0(Object _, String message) in /Users/chris/Developer/Projects/AsExPoC/AsExPoC/DummyService.cs:line 36
at AsExPoC.DummyMessenger.StartReceiving() in /Users/chris/Developer/Projects/AsExPoC/AsExPoC/DummyMessenger.cs:line 27
at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__140_1(Object state)
at System.Threading.QueueUserWorkItemCallbackDefaultContext.Execute()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
感谢反馈。
我首先将您的长 运行 服务移动到 IHostedService
,如果服务停止,则强制主机停止;
public class DummyService : BackgroundService
{
private readonly IHostApplicationLifetime lifetime;
public DummyService(IHostApplicationLifetime lifetime)
{
this.lifetime = lifetime;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (true)
{
//...
}
}
catch (Exception)
{
Environment.ExitCode = 8;
}
lifetime.StopApplication();
}
}
然后你可以从你的 main 方法 return Environment.ExitCode
,或者将它保留为 void
return.
我的 .NET5 Web API 项目(除了 REST)监听 Telegram 消息。目标很简单:
- 当用户发送 exit 消息时 - 使用退出代码 8 终止应用程序
- 当消息处理程序抛出 SeriousException - 使用退出代码 8 终止应用程序
不幸的是,由于消息轮询的异步特性,我正在努力实现这个目标。我在 GitHub 中准备了一个示例项目:https://github.com/chris-rutkowski/AsExPoC .
我在 Stack Overflow 上发现了许多类似的主题,但对我来说没有什么真正有用,而且大量建议的解决方案(一些 AsyncHelpers 等)似乎有点过分。我正在考虑将 Thread.CurrentThread
传递给服务并以某种方式在其上抛出异常,但我不知道如何,或者它是否可能发生,即使可能发生,这是否是最佳实践。我对 C#+.NET 了解不多,但在 Swift (iOS) 中,我会很容易地解决它,只需 3 行包括大括号:
DispatchQueue.main.async {
throw ForcedExitException()
}
这是我精简的 .NET5 Web Api,您可以在 repo.
中找到Program.cs
public class Program
{
public static int Main(string[] args)
{
try
{
var host = CreateHostBuilder(args).Build();
var service = host.Services.GetRequiredService<DummyService>();
service.Run();
// other services are running too - I cannot just wait for DummyService to throw the exception
host.Run();
return 0;
}
catch (ForcedExitException)
{
return 8;
}
catch (Exception ex)
{
return 1;
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
DummyService.cs
public class DummyService
{
private readonly DummyMessenger _dummyMessenger;
public DummyService()
{
_dummyMessenger = new DummyMessenger();
}
public async void Run()
{
_dummyMessenger.StartReceiving();
_dummyMessenger.Add(async (_, message) => {
Console.WriteLine($"received message {message}");
await Task.Delay(50);
if (message == "exit")
throw new ForcedExitException();
});
}
}
我的期望:
Exited with error code 8
这是我在控制台中看到的:
Exited with error code 134, with the following stacktrace
Unhandled exception. AsExPoC.ForcedExitException: Exception of type 'AsExPoC.ForcedExitException' was thrown.
at AsExPoC.DummyService.<>c.<Run>b__2_0(Object _, String message) in /Users/chris/Developer/Projects/AsExPoC/AsExPoC/DummyService.cs:line 36
at AsExPoC.DummyMessenger.StartReceiving() in /Users/chris/Developer/Projects/AsExPoC/AsExPoC/DummyMessenger.cs:line 27
at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__140_1(Object state)
at System.Threading.QueueUserWorkItemCallbackDefaultContext.Execute()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
感谢反馈。
我首先将您的长 运行 服务移动到 IHostedService
,如果服务停止,则强制主机停止;
public class DummyService : BackgroundService
{
private readonly IHostApplicationLifetime lifetime;
public DummyService(IHostApplicationLifetime lifetime)
{
this.lifetime = lifetime;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (true)
{
//...
}
}
catch (Exception)
{
Environment.ExitCode = 8;
}
lifetime.StopApplication();
}
}
然后你可以从你的 main 方法 return Environment.ExitCode
,或者将它保留为 void
return.