首先,我决定使用Hangfire,因为它可以在不同的Windows服务中运行代码,或者实际上可以在不同的服务器上运行代码。我可以使用Task类轻松地执行我的任务,但是我的逻辑将在很长一段时间内24/7运行,直到它被用户停止为止,而且我认为任务无法处理。所以我才用汉弗莱。我对不同的解决方案持开放态度。更具体地说,我的逻辑是使用web套接字24/7监控东西。
如果您看下面的代码,它有一个运行方法,它在来自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,但是即使在BackgroundJob.Delete(jobId)调用之后,if (token.IsCancellationRequested)也不会被触发。
我还使用Redis来存储作业id。也编辑了上面的代码。
发布于 2021-11-25 07:06:18
要取消Hangfire作业,您不必提供自己的CancellationToken。相反,您提供给Hangfire的排队方法需要一个该类型的参数。当通过代码对作业进行查询时,在这种情况下,默认的CancellationToken.None和Hangfire会注意在执行方法时提供真正的令牌。在您的方法中,您可以常规地询问令牌的状态,如果需要的话退出。
若要取消正在运行的作业,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);
}https://stackoverflow.com/questions/59539078
复制相似问题