我有一个每 X 秒运行一次的作业,在 WindowsService 中运行该作业的执行时间不应长(少于 5 秒)。我的目标是确保当前正在运行的作业在 Windows 服务在执行过程中停止时完成其执行。
这个线程看起来很有趣,但到目前为止它不起作用:应用程序关闭时的任务处理
任何帮助将不胜感激。
WindowsService 实现:
public partial class WindowsService : ServiceBase
{
private readonly ILogger logger;
private readonly IStartJob startJob;
private readonly CancellationTokenSource cancellationTokenSource;
private Task task;
public WindowsService(IStartJob startJob, ILogger logger)
{
// Dependancy injection of logger and JobStarter
this.startJob = startJob;
this.logger = logger;
InitializeComponent();
cancellationTokenSource = new CancellationTokenSource();
}
protected override void OnStart(string[] args)
{
task = new Task(() => startJob.Start(cancellationTokenSource.Token),
cancellationTokenSource.Token, TaskCreationOptions.LongRunning);
task.Start();
logger.Info("Service started");
}
protected override void OnStop()
{
RequestAdditionalTime(TimeSpan.FromSeconds(30).Milliseconds);
cancellationTokenSource.Cancel();
try { task.Wait(); }
catch (Exception ex) { logger.Error("Error while stopping the Service", ex); }
logger.Info("Service stopped");
}
}
启动作业实现:
public class StartJob : IStartJob
{
private readonly ILogger logger;
private readonly IExecuteJob executeJob;
private DateTime lastExecution = DateTime.UtcNow.AddDays(-1);
public StartJob(ILogger logger, IExecuteJob executeJob)
{
this.logger = logger;
this.executeJob = executeJob;
}
public async void Start(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
var nextExecution = lastExecution.AddSeconds(5);
if (nextExecution < DateTime.UtcNow)
{
try
{
logger.Info("Start Job Execution");
// To similate long process not ended, break point here
// and stop the service before continuing the execution.
Thread.Sleep(5000);
executeJob.Execute();
logger.Info("Job completed");
AdjustLastExecution(nextExecution);
}
catch (Exception ex)
{
logger.Error("Unexpected exception while executing job", ex);
}
}
// Would expect the cancelToken to activate here or in the while condition
await Task.Delay(TimeSpan.FromSeconds(1), token);
}
}
private void AdjustLastExecution(DateTime nextExecution)
{
// To ensure we have an heartbeat close to 5 seconds
lastExecution = nextExecution.AddSeconds(5) > DateTime.UtcNow ?
nextExecution : DateTime.UtcNow.AddSeconds(-5);
}
}
我尝试了一堆变体,输入任务中存在的 cancelToken,任务等待和等待毫秒超时,但到目前为止没有任何效果。
我将我的解决方案附加到正在执行的 WindowsService,并确保正在执行的作业将位于其中的中间,其中包含断点和 Thread.Sleep。但是,不会写入作业已完成日志,并且在其之前会删除附加的已处理日志。
我很快看了你的代码,我唯一会尝试的是
替换 :
async void
跟
async Task
我不保证它适用于您的情况,但我记得阅读这篇文章建议避免异步无效。
在 C# 中,异步 void 方法是代码的祸害。
Haacked.com |避免异步无效方法
编辑:
task = new Task(() => startJob.Start(cancellationTokenSource.Token),
cancellationTokenSource.Token, TaskCreationOptions.LongRunning);
跟
task = startJob.Start(cancellationTokenSource.Token);