gpt4 book ai didi

c# - 如何停止和恢复 worker 服务?

转载 作者:行者123 更新时间:2023-12-05 01:37:01 29 4
gpt4 key购买 nike

在 WPF 应用程序中,我配置了一个托管服务以在后台执行特定事件(遵循 this article)。这就是在 App.xaml.cs 中配置托管服务的方式。

public App()
{
var environmentName = Environment.GetEnvironmentVariable("HEALTHBOOSTER_ENVIRONMENT") ?? "Development";
IConfigurationRoot configuration = SetupConfiguration(environmentName);
ConfigureLogger(configuration);
_host = Host.CreateDefaultBuilder()
.UseSerilog()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>()
.AddOptions()
.AddSingleton<IMailSender, MailSender>()
.AddSingleton<ITimeTracker, TimeTracker>()
.AddSingleton<NotificationViewModel, NotificationViewModel>()
.AddTransient<NotificationWindow, NotificationWindow>()
.Configure<AppSettings>(configuration.GetSection("AppSettings"));
}).Build();

AssemblyLoadContext.Default.Unloading += Default_Unloading;

Console.CancelKeyPress += Console_CancelKeyPress;

SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
}

并在启动时开始

/// <summary>
/// Handles statup event
/// </summary>
/// <param name="e"></param>
protected override async void OnStartup(StartupEventArgs e)
{
try
{
Log.Debug("Starting the application");
await _host.StartAsync(_cancellationTokenSource.Token);
base.OnStartup(e);
}
catch (Exception ex)
{
Log.Error(ex, "Failed to start application");
await StopAsync();
}
}

现在我想在系统进入休眠状态时停止托管服务,并在系统恢复时重新启动服务。我试过了

/// <summary>
/// Handles system suspend and resume events
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
switch (e.Mode)
{
case PowerModes.Resume:
Log.Warning("System is resuming. Restarting the host");
try
{
_cancellationTokenSource = new CancellationTokenSource();
await _host.StartAsync(_cancellationTokenSource.Token);
}
catch (Exception ex)
{
Log.Error(ex, $"{ex.Message}");
}
break;

case PowerModes.Suspend:
Log.Warning("System is suspending. Canceling the activity");
_cancellationTokenSource.Cancel();
await _host.StopAsync(_cancellationTokenSource.Token);
break;
}
}

停止主机工作正常但是当主机重新启动时,我收到“System.OperationCanceledException”。根据我的理解,托管服务生命周期独立于应用程序生命周期。我的理解错了吗?

这个问题- ASP.NET Core IHostedService manual start/stop/pause(?)是相似的,但答案是暂停并重新启动基于配置的服务,这看起来像是 hack,所以我正在寻找一种标准方法。

有什么想法吗?

最佳答案

作为Stephen Cleary在评论中指出,worker 可以独立于主机启动和停止,但理想情况下主机应该处理 worker 的生命周期。
但是由于 .NET Core 3 中存在一个错误,传递给 IHostedService StartAsync 方法的取消标记不会传播给工作人员 ExecuteAsync 方法。我为此创建了一个问题,可以在此处找到详细信息 - https://github.com/dotnet/extensions/issues/3218

错误修复 (https://github.com/dotnet/extensions/pull/2823) 将成为 .NET 5 的一部分,因此按照问题 (https://github.com/dotnet/extensions/issues/3218#issuecomment-622503957) 中的建议,我必须创建自己的类来模仿框架的 BackGroundService 类并且此类将直接继承自 IHostedService 并将取消 token 传播给工作人员。

BackGroundService 类自定义实现在这里 -

/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BGService : IHostedService, IDisposable
{
private Task _executingTask;
private CancellationTokenSource _stoppingCts;

/// <summary>
/// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
/// the lifetime of the long running operation(s) being performed.
/// </summary>
/// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
/// <returns>A <see cref="Task"/> that represents the long running operations.</returns>
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

/// <summary>
/// Triggered when the application host is ready to start the service.
/// </summary>
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Create linked token to allow cancelling executing task from provided token
_stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token);

// If the task is completed then return it, this will bubble cancellation and failure to the caller
if (_executingTask.IsCompleted)
{
return _executingTask;
}

// Otherwise it's running
return Task.CompletedTask;
}

/// <summary>
/// Triggered when the application host is performing a graceful shutdown.
/// </summary>
/// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
}

try
{
// Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
}

}

public virtual void Dispose()
{
_stoppingCts?.Cancel();
}
}

以及分别在系统挂起和恢复时停止和启动worker的逻辑

/// <summary>
/// Handles system suspend and resume events
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
var workers = _host.Services.GetServices<IHostedService>();
Log.Information($"Found IHostedService instances - {workers.ToCSV()}");
switch (e.Mode)
{
case PowerModes.Resume:
Log.Warning("System is resuming. Restarting the workers");
try
{
_cancellationTokenSource = new CancellationTokenSource();
foreach (var worker in workers)
{
await worker.StartAsync(_cancellationTokenSource.Token);
}
}
catch (Exception ex)
{
Log.Error(ex, $"{ex.Message}");
}
break;

case PowerModes.Suspend:
Log.Warning("System is suspending. Stopping the workers");
_cancellationTokenSource.Cancel();
try
{
foreach (var worker in workers)
{
await worker.StopAsync(_cancellationTokenSource.Token);
}
}
catch (Exception ex)
{
Log.Error(ex, $"{ex.Message}");
}
break;
}
}

请注意@davidfowl 建议这不是受支持的功能 (https://github.com/dotnet/extensions/issues/3218#issuecomment-623280990),但我在使用这种方法时没有遇到任何问题,并且相信这也应该是受支持的用例。

关于c# - 如何停止和恢复 worker 服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61496138/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com