首先,我决定使用 Hangfire,因为它可以在不同的 Windows 服务中或者实际上在不同的服务器上运行代码。我可以使用
Task
类轻松执行任务,但我的逻辑将 24/7 运行很长一段时间,直到被用户停止,我不认为任务可以处理这个问题。这就是我使用 Hangfire 的原因。我对不同的解决方案持开放态度。更具体地说,我的逻辑是使用网络套接字 24/7 监控东西。
如果你看下面我的代码,它有 Run 方法,可以在 Hangfire 的 BackgroundJob 中生成一个新的机器人。问题是,当我必须停止特定的机器人(比方说“机器人 1”)时,它应该以某种方式识别当前无法识别的机器人。
Hangfire 的文档不完整,或者至少我不明白如何从所写的内容中做到这一点。 https://docs.hangfire.io/en/latest/background-methods/using-cancellation-tokens.html
private UpdateSubscription _subscription;
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
public async Task RunAsync(string botName)
{
var jobId = BackgroundJob.Enqueue(() => StartAsync(botName, _cts.Token));
await _cache.SetAsync($"bot_{botName.Replace(" ", "_")}", jobId);
}
public void Start(Bot bot, CancellationToken token)
{
// heavy logic
_subscription = _socketClient.SubscribeToKlineUpdates(bot.CryptoPair.Symbol, bot.TimeInterval.Interval /*KlineInterval.OneHour*/, async data =>
{
... logic ...
if (token.IsCancellationRequested)
{
await _socketClient.Unsubscribe(_subscription);
}
}
}
public async Task StopAsync(string botName)
{
var jobId = await _cache.GetAsync<string>($"bot_{botName.Replace(" ", "_")}");
if (jobId == null)
return;
BackgroundJob.Delete(jobId);
}
编辑:BackgroundJob 将 jobId 作为字符串返回,但不知何故,即使在
if (token.IsCancellationRequested)
调用之后也永远不会触发 BackgroundJob.Delete(jobId)
。
我还使用Redis来存储作业ID。也编辑了上面的代码。
要取消 Hangfire 作业,您无需提供自己的 CancellationToken。相反,您提供给 Hangfire 的排队方法需要该类型的参数。当通过代码排队作业时,您在这种情况下提供默认的
CancellationToken.None
,并且 Hangfire 会在执行方法时小心地提供 real 标记。在您的方法中,您定期询问令牌的状态并根据需要退出。
要取消正在运行的作业,Hangfire 本身会监视两个事件来触发所提供的令牌。服务器收到关闭请求(这会将作业置于新的排队状态以便在下次启动时再次运行)或作业删除请求。
以下是一些代码草图:
// The method initiated from Hangfire Worker with special parameters
// for cancellationToken and context, filled by Hangfire.
public async Task MyJob(int someParameter, CancellationToken cancellationToken, PerformContext context)
{
for (int i = 0; i < 100; i++)
{
cancellationToken.ThrowIfCancellationRequested();
Console.WriteLine($"Processing {i} in job {context.Job.Id}");
await DoSomething(i, cancellationToken);
}
}
private string EnqueueMyJob(int someParameter)
{
// When enqueuing a job, just provide some default values for the *magic parameters*
return jobClient.Enqueue<MyTaskClass>(task => task.MyJob(someParameter, CancellationToken.None, null));
}
private void CancelMyJob(string jobId)
{
// If the job is currently running, the cancellation token will be set.
jobClient.Delete(jobId);
}
目前,我使用的是 Hangfire 1.8.7 版本。在此版本中,jobClient.Delete(jobId) 出现错误。为了解决这个问题,我尝试使用以下代码片段:
BackgroundJobClient backgroundJobClient = new BackgroundJobClient();
backgroundJobClient.Delete(JobId);