c# - 重复启动和停止 Worker Service
问题描述
该项目中有两个文件,program.cs
用于操作服务和worker.cs
包含服务逻辑的文件。在里面program.cs
,我使用如下方法来操作服务:
// program.cs (partially)
public static void Main(string[] args)
{
while (true)
{
string a = client.ReceiveFrameString(); // To receive a flag from external programs to start the service
if (bool.Parse(a))
{
Console.WriteLine("START");
Thread t = new Thread(new ParameterizedThreadStart(ThreadProc));
t.Start(args);
CreateHostBuilder(args).Build().RunAsync().Wait(); // This works at the first start
// ATTENTION! CreateHostBuilder(args).Build().Run() will return an error about args.Length < 0
Console.WriteLine("DONE Start");
}
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
});
public static void ThreadProc(object obj)
{
string[] args = ToStringArray(obj);
while (true)
{
string temp = recv.ReceiveFrameString(); // To receive a flag from external programs to stop the service
if (!bool.Parse(temp))
{
Console.WriteLine("STOP");
CreateHostBuilder(args).Build().StopAsync().Wait();
Console.WriteLine("DONE Stop");
break; // Jump out of the loop as soon as the service is stopped.
}
}
}
如您所见,我正在使用一个 while 循环来创建一个“Start-Stop”集,其中包含启动服务的命令和一个在从外部源触发时停止服务的线程。我可以根据 BackgroundService 类中覆盖的 StartAsync 和 StopAsync 方法中的日志输出来观察服务是否成功启动和停止,如下所示:
// worker.cs (partially)
public override async Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("STARTED!!");
await base.StartAsync(cancellationToken);
}
public override async Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("STOPPED!!");
await base.StopAsync(cancellationToken);
}
现在启动服务的命令在第一次触发时工作,但是在成功调用线程时 StopAsync 没有按预期工作。
作为预期的结果,我希望该服务能够反复启动和停止。这之下有什么问题?有没有解决方案?
编辑 1
最小可重现示例位于此处。
编辑 2(更新)
经过几天对堆栈溢出和 MSDN 的研究,我终于在我的场景中找到了一个可能的解决方案。
起初,根据this answer,我确定我的应用程序不是长期服务,所以我删除了Worker Service Template中的“repeat-until-your-BackgroundService-is-stopped”-loop:
// From worker.cs
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// Remove the while loop
/*while (!stoppingToken.IsCancellationRequested)
{
// _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
// await Task.Delay(1000, stoppingToken);
}*/
}
其次,根据这个 MSDN C# API aboutRunAsync(IHost, CancellationToken)
,我可以创建一个 CancellationSource ,它可以生成一个 CancellationToken 来取消它。与文档中给出的示例类似,我可以通过取消源来关闭工作者。因此,实现变为:
// From program.cs
public static void Main(string[] args)
{
while (true)
{
string a = client.ReceiveFrameString(); // To receive a flag from external programs to start the service
if (bool.Parse(a))
{
Console.WriteLine("START");
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
Thread t = new Thread(new ParameterizedThreadStart(ThreadProc));
t.Start(source);
CreateHostBuilder(args).Build().RunAsync(token);
Console.WriteLine("DONE Start");
}
}
}
public static void ThreadProc(object obj)
{
var source = obj as CancellationTokenSource;
while (true)
{
string temp = recv.ReceiveFrameString(); // To receive a flag from external programs to stop the service
if (!bool.Parse(temp))
{
Console.WriteLine("STOP");
source.Cancel();
source.Dispose();
Console.WriteLine("DONE Stop");
break; // Jump out of the loop as soon as the service is stopped.
}
}
}
但是,此解决方案不适用于具有“repeat-until-your-BackgroundService-is-stopped”循环的工作人员。似乎 CancellationToken 无法在worker.cs
. 这应该是现在要问的问题:如何使用“repeat-until-your-BackgroundService-is-stopped”-loop来启动和停止worker服务?
原来的 Minimal Producible Example 现在根据 EDIT 2 进行了调整。
解决方案
推荐阅读
- sql - 使用 XMLtable 列。是否可以将集合数据类型分配给 xmltable 列
- javascript - Express:使用 HTTP/2 时如何获取 Host 标头
- spring-boot - MultiResourceItemReader 未按预期工作
- python-3.x - 基于时间的 Python 条件
- flutter - 给新手 Flutter 开发者的提示
- java - 单击打印按钮后硒步骤被阻止
- customization - nav-toc 不适用于 DITA-OT 中的主题
- ietf-netmod-yang - 杨建模语言 - 在位类型中选择/取消选择一个或多个选项
- java - 如何使用 simple_list_item_2 布局和两个数组(android studio)?
- css - 悬停在“父链接”下时如何停止下拉菜单?