You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core Worker Service实现长时间运行操作:创建、取消、暂停与恢复

.NET Worker Service 取消、暂停与结果存储最佳实践及开源示例

核心功能实现最佳实践

任务取消

  • 基于.NET原生CancellationToken机制实现,为每个任务关联唯一的CancellationTokenSource(CTS),并通过内存字典或分布式缓存存储任务ID与CTS的映射。
  • API接收取消请求时,根据任务ID找到对应的CTS并调用Cancel(),任务执行过程中定期检查IsCancellationRequested,优雅终止流程并释放资源。
  • 代码示例:
// 存储任务取消令牌源(生产环境建议用分布式缓存替代内存字典)
private readonly Dictionary<Guid, CancellationTokenSource> _taskCtsMap = new();

// 启动任务时绑定CTS
public async Task EnqueueLongRunningTaskAsync(Guid taskId)
{
    var cts = new CancellationTokenSource();
    _taskCtsMap.TryAdd(taskId, cts);
    
    await _backgroundTaskQueue.QueueBackgroundWorkItemAsync(async token =>
    {
        try
        {
            await ExecuteLongRunningTask(taskId, cts.Token);
        }
        finally
        {
            _taskCtsMap.TryRemove(taskId, out _);
            cts.Dispose();
        }
    });
}

// 处理取消请求
public void CancelTask(Guid taskId)
{
    if (_taskCtsMap.TryGetValue(taskId, out var cts))
        cts.Cancel();
}

任务暂停/恢复

  • 使用ManualResetEventSlim作为暂停信号量,为每个任务维护一个实例,初始状态设为Set()(非暂停)。
  • 任务执行片段中插入信号量等待逻辑,触发暂停时调用Reset()阻塞任务,恢复时调用Set()继续执行。注意结合CancellationToken避免无限阻塞。
  • 代码示例:
private readonly Dictionary<Guid, ManualResetEventSlim> _taskPauseEvents = new();

// 启动任务时初始化暂停事件
public async Task EnqueueTaskWithPauseSupport(Guid taskId)
{
    var pauseEvent = new ManualResetEventSlim(true);
    _taskPauseEvents.TryAdd(taskId, pauseEvent);
    
    await _backgroundTaskQueue.QueueBackgroundWorkItemAsync(async token =>
    {
        try
        {
            while (!token.IsCancellationRequested)
            {
                pauseEvent.Wait(token); // 检查暂停状态,支持取消
                await ExecuteTaskSegmentAsync(token);
            }
        }
        finally
        {
            _taskPauseEvents.TryRemove(taskId, out _);
            pauseEvent.Dispose();
        }
    });
}

// 暂停任务
public void PauseTask(Guid taskId)
{
    if (_taskPauseEvents.TryGetValue(taskId, out var evt))
        evt.Reset();
}

// 恢复任务
public void ResumeTask(Guid taskId)
{
    if (_taskPauseEvents.TryGetValue(taskId, out var evt))
        evt.Set();
}

结果与状态存储

  • 设计任务状态表记录全生命周期数据,核心字段包括:TaskId(主键)、Status(枚举:待执行/运行中/已取消/已完成/失败)、Progress(进度百分比)、Result(JSON格式存储结果)、ErrorMessage、CreatedAt、UpdatedAt。
  • 任务执行过程中定期更新进度和状态,完成或失败时写入最终结果;API层可通过查询该表返回任务状态和结果。
  • 代码示例(EF Core):
public async Task UpdateTaskProgressAsync(Guid taskId, int progress, string? status = null)
{
    await _dbContext.TaskStatuses
        .Where(t => t.TaskId == taskId)
        .ExecuteUpdateAsync(s => s
            .SetProperty(t => t.Progress, progress)
            .SetProperty(t => t.UpdatedAt, DateTime.UtcNow)
            .SetPropertyIfNotNull(t => t.Status, status));
}

开源参考项目

  • Hangfire:成熟的后台任务管理库,内置任务取消、状态跟踪、结果存储功能,支持SQL Server、Redis等多种存储后端,可无缝集成到Worker Service中。
  • MassTransit:与RabbitMQ深度集成的分布式消息框架,通过Saga模式实现复杂任务的暂停、恢复与状态管理,适合分布式场景下的任务处理。
  • Microsoft Background Tasks Sample:官方提供的后台任务队列示例,包含任务取消、队列管理的基础实现,可作为扩展暂停和结果存储功能的起点。

内容的提问来源于stack exchange,提问作者Praveen Kumar N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 03:22:40