worker是事件驱动的时候应该BackgroundService.ExecuteAsyncreturn怎么办?
What should BackgroundService.ExecuteAsync return when the worker is event-driven?
Worker Service 是在 .NET Core 3.x 中编写 Windows 服务的新方法。 worker class 扩展 Microsoft.Extensions.Hosting.BackgroundService
并实现 ExecuteAsync
。该方法的文档说:
This method is called when the IHostedService starts. The implementation should return a task that represents the lifetime of the long running operation(s) being performed.
当服务完成的工作不是通常意义上的长运行操作,而是事件驱动时,这个方法return应该怎么办?例如,我正在编写一个设置 FileSystemWatcher
的服务。我如何将其封装在 Task
中?没有 Task.Never()
,所以我应该 return 基于很长 Task.Delay()
的东西来防止服务关闭吗?
private async Task DoStuffAsync(CancellationToken cancel)
{
// register events
while(!cancel.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromDays(1000000), cancel);
}
// unregister events
}
我将延迟合并到一个名为 Eternity
的方法中:
private async Task Eternity(CancellationToken cancel)
{
while (!cancel.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromDays(1), cancel);
}
}
所以我的 ExecuteAsync
看起来像:
protected override async Task ExecuteAsync(CancellationToken cancel)
{
using (var watcher = new FileSystemWatcher())
{
ConfigureWatcher(watcher);
await Eternity(cancel);
}
}
这似乎符合预期。
您也可以使用实际的无限延迟:
await Task.Delay(Timeout.Infinite, cancellationToken);
如果您想像 await "Eternity"
或 await ("Eternity", token)
那样称呼它(如果您想要取消支持)。多亏了值元组,我们可以在取消支持下使用它们。
基本上你可以用一些扩展方法等待任何东西。
代码如下:
protected override async Task ExecuteAsync(CancellationToken token)
{
using (var watcher = new FileSystemWatcher())
{
ConfigureWatcher(watcher);
// Use any of these methods you'd like
await "Eternity";
await ("Eternity", token);
await TimeSpan.FromDays(1);
await (TimeSpan.FromDays(1), token);
}
}
public static class GetAwaiterExtensions
{
public static TaskAwaiter GetAwaiter(this (TimeSpan, CancellationToken) valueTuple)
{
return Task.Delay((int) valueTuple.Item1.TotalMilliseconds, valueTuple.Item2)
.GetAwaiter();
}
public static TaskAwaiter GetAwaiter(this TimeSpan timeSpan)
{
return Task.Delay((int) timeSpan.TotalMilliseconds)
.GetAwaiter();
}
public static TaskAwaiter GetAwaiter(this string value)
{
if (value == "Eternity")
{
return Task.Delay(Timeout.Infinite)
.GetAwaiter();
}
throw new ArgumentException();
}
public static TaskAwaiter GetAwaiter(this (string, CancellationToken) valueTuple)
{
if (valueTuple.Item1 == "Eternity")
{
return Task
.Delay(Timeout.Infinite, cancellationToken: valueTuple.Item2)
.GetAwaiter();
}
throw new ArgumentException();
}
}
Worker Service 是在 .NET Core 3.x 中编写 Windows 服务的新方法。 worker class 扩展 Microsoft.Extensions.Hosting.BackgroundService
并实现 ExecuteAsync
。该方法的文档说:
This method is called when the IHostedService starts. The implementation should return a task that represents the lifetime of the long running operation(s) being performed.
当服务完成的工作不是通常意义上的长运行操作,而是事件驱动时,这个方法return应该怎么办?例如,我正在编写一个设置 FileSystemWatcher
的服务。我如何将其封装在 Task
中?没有 Task.Never()
,所以我应该 return 基于很长 Task.Delay()
的东西来防止服务关闭吗?
private async Task DoStuffAsync(CancellationToken cancel)
{
// register events
while(!cancel.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromDays(1000000), cancel);
}
// unregister events
}
我将延迟合并到一个名为 Eternity
的方法中:
private async Task Eternity(CancellationToken cancel)
{
while (!cancel.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromDays(1), cancel);
}
}
所以我的 ExecuteAsync
看起来像:
protected override async Task ExecuteAsync(CancellationToken cancel)
{
using (var watcher = new FileSystemWatcher())
{
ConfigureWatcher(watcher);
await Eternity(cancel);
}
}
这似乎符合预期。
您也可以使用实际的无限延迟:
await Task.Delay(Timeout.Infinite, cancellationToken);
如果您想像 await "Eternity"
或 await ("Eternity", token)
那样称呼它(如果您想要取消支持)。多亏了值元组,我们可以在取消支持下使用它们。
基本上你可以用一些扩展方法等待任何东西。
代码如下:
protected override async Task ExecuteAsync(CancellationToken token)
{
using (var watcher = new FileSystemWatcher())
{
ConfigureWatcher(watcher);
// Use any of these methods you'd like
await "Eternity";
await ("Eternity", token);
await TimeSpan.FromDays(1);
await (TimeSpan.FromDays(1), token);
}
}
public static class GetAwaiterExtensions
{
public static TaskAwaiter GetAwaiter(this (TimeSpan, CancellationToken) valueTuple)
{
return Task.Delay((int) valueTuple.Item1.TotalMilliseconds, valueTuple.Item2)
.GetAwaiter();
}
public static TaskAwaiter GetAwaiter(this TimeSpan timeSpan)
{
return Task.Delay((int) timeSpan.TotalMilliseconds)
.GetAwaiter();
}
public static TaskAwaiter GetAwaiter(this string value)
{
if (value == "Eternity")
{
return Task.Delay(Timeout.Infinite)
.GetAwaiter();
}
throw new ArgumentException();
}
public static TaskAwaiter GetAwaiter(this (string, CancellationToken) valueTuple)
{
if (valueTuple.Item1 == "Eternity")
{
return Task
.Delay(Timeout.Infinite, cancellationToken: valueTuple.Item2)
.GetAwaiter();
}
throw new ArgumentException();
}
}