Fork me on GitHub
线程监测帮助类

线程监测帮助类,可以帮助我们管理task任务

SQL

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for taskinfo
-- ----------------------------
DROP TABLE IF EXISTS `taskinfo`;
CREATE TABLE `taskinfo`  (
  `TaskId` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '线程Id',
  `TaskName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '线程名称',
  `State` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '线程执行状态',
  `CurrentTime` datetime NOT NULL COMMENT '运行时间',
  PRIMARY KEY (`TaskId`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;

SET FOREIGN_KEY_CHECKS = 1;

C# code

/// <summary>
/// 线程监测帮助类
/// </summary>
public class ThreadTaskMonitor
{
    public static ConcurrentBag<TaskInfo> ThreadTaskList = new ConcurrentBag<TaskInfo>();
    private static int IntervalTimeSave = 1000 * 10; //多长时间保存一次数据
    private static readonly ILogger<ThreadTaskMonitor> _logger;
    static ThreadTaskMonitor()
    {
        _logger = ServiceLocator.Instance.GetRequiredService<ILogger<ThreadTaskMonitor>>();

        Initialize();

        SaveData(IntervalTimeSave);
    }

    /// <summary>
    /// 添加任务线程
    /// </summary>
    /// <param name="taskName">线程名称</param>
    /// <param name="action">线程方法名</param>
    /// <param name="milliSeconds">毫秒</param>
    /// <returns>成功返回true,是否返回false</returns>
    public static bool AddThreadTask(string taskName, Action action, int milliSeconds = 10)
    {
        if(ThreadTaskList.Any(t=>t.TaskName == taskName))
        {
            //Trace.Assert(false, $"Task任务中已存在该名称{taskName}的任务!");
            Console.WriteLine($"Task任务中已存在该名称{taskName}的任务!");
            _logger.LogError($"Task任务中已存在该名称{taskName}的任务!");
            return false;
        }

        var taskInfo = new TaskInfo(taskName);
        taskInfo.ActionFunction = action;
        taskInfo.Task = Task.Run(()=>{
            //await Task.Delay(milliSeconds);
            Thread.Sleep(milliSeconds);
            action?.Invoke();
        });

        ThreadTaskList.Add(taskInfo);
        return true;
    }

    /// <summary>
    /// 添加任务线程
    /// </summary>
    /// <param name="info">任务线程对象</param>
    /// <returns>成功返回true,是否返回false</returns>
    public static bool AddThreadTask(TaskInfo info)
    {
        if (ThreadTaskList.Any(t => t.TaskName == info.TaskName))
        {
            //Trace.Assert(false, $"Task任务中已存在该名称{info.TaskName}的任务!");
            Console.WriteLine($"Task任务中已存在该名称{ info.TaskName}的任务!");
            _logger.LogError($"Task任务中已存在该名称{info.TaskName}的任务!");
            return false;
        }

        ThreadTaskList.Add(info);
        return true;
    }

    /// <summary>
    /// 初始化开始监测所有线程,如果线程出现异常,则重新启动线程
    /// </summary>
    private static void Initialize()
    {
        Task.Run(() =>
        {
            while (true)
            {
                foreach (TaskInfo info in ThreadTaskList)
                {
                    if (info.Task == null)
                    {
                        info.State = TaskStatus.Faulted.ToString();
                        info.CurrentTime = DateTime.Now;
                    }
                    else
                    {
                        info.State = info.Task.Status.ToString();
                        info.CurrentTime = DateTime.Now;

                        if (info.Task.IsFaulted)
                        {
                            try
                            {
                                Thread.Sleep(1000);
                                Debug.WriteLine($"{DateTime.Now}: {info.TaskName} 重新启动!");
                                _logger.LogInformation($"{DateTime.Now}: {info.TaskName} 重新启动!");
                                info.Task = Task.Run(() => { info.ActionFunction?.Invoke(); });
                                info.State = info.Task.Status.ToString();
                                info.CurrentTime = DateTime.Now;
                            }
                            catch (Exception ex)
                            {
                                _logger.LogError($"任务:{info.TaskName} 启动失败!");
                            }
                            
                        }
                    }
                }

                Thread.Sleep(5000);
            }
        });
    }

    /// <summary>
    /// 将线程状态更新到数据库中
    /// </summary>
    /// <param name="tervalTime"></param>
    private static void SaveData(int tervalTime)
    {
        var _serviceScopeFactory = ServiceLocator.Instance.GetRequiredService<IServiceScopeFactory>();
        var _dataContext = _serviceScopeFactory.CreateScope().ServiceProvider.GetRequiredService<DataContext>();
        List<TaskInfo> taskInfoAddList = new List<TaskInfo>(); // 新增
        List<TaskInfo> taskInfoUpdateList = new List<TaskInfo>(); // 更新

        Task.Run(() =>
        {
            while (true)
            {
                try
                {
                    taskInfoAddList.Clear();
                    taskInfoUpdateList.Clear();
                    var taskInfoList = _dataContext.TaskInfos.AsQueryable();
                    var taskList = ThreadTaskList;
                    TaskInfo taskInfoTemp;
                    foreach (var task in taskList)
                    {
                        taskInfoTemp = taskInfoList.Where(t => t.TaskName == task.TaskName).FirstOrDefault();

                        if (task.State == null) task.State = "Created";
                        if (taskInfoTemp == null)
                        {
                            taskInfoAddList.Add(task);
                        }
                        else
                        {
                            taskInfoTemp.State = task.State;
                            taskInfoTemp.CurrentTime = task.CurrentTime;
                            taskInfoUpdateList.Add(taskInfoTemp);
                        }

                        //Console.WriteLine(task.ToString());
                    }


                    if (taskInfoAddList.Count > 0)
                        _dataContext.TaskInfos.AddRange(taskInfoAddList);

                    if (taskInfoUpdateList.Count > 0)
                        _dataContext.TaskInfos.UpdateRange(taskInfoUpdateList);

                    if (!taskList.IsEmpty)
                        _dataContext.SaveChanges();
                }
                catch (Exception ex)
                {
                    //Console.WriteLine(ex.Message);
                    _logger.LogError("线程监控更新数据异常:" + ex.Message);
                }


                Thread.Sleep(tervalTime);
            }
        });
    }

}

优化和重构代码是提升代码质量、可维护性和性能的重要步骤。以下是对您提供的 ThreadTaskMonitor 类的详细优化和重构建议,包括代码示例和专业分析。

主要优化和重构点

  1. 使用 CancellationToken 管理任务的生命周期:

    • 通过引入 CancellationToken,可以优雅地停止任务监控和数据保存,避免使用无限循环和 Thread.Sleep
  2. 减少代码重复:

    • AddThreadTask 方法有两个重载,逻辑重复。可以通过合并这两个方法来减少代码重复。
  3. 使用 async/await 代替 Thread.Sleep

    • 使用 Task.Delay 替代 Thread.Sleep,使代码更具可读性和异步友好。
  4. 引入 ConcurrentDictionary 替代 ConcurrentBag

    • 使用 ConcurrentDictionary 可以更高效地查找和管理任务,避免在添加任务时进行遍历。
  5. 改进异常处理:

    • 细化异常处理,确保异常信息能够提供更多上下文,并在必要时进行重试。
  6. 使用 IHostedService 或 BackgroundService

    • 如果这是一个 ASP.NET Core 应用,可以将监控逻辑封装到一个后台服务中,利用 DI 和生命周期管理。

重构后的代码示例

using System;  
using System.Collections.Concurrent;  
using System.Linq;  
using System.Threading;  
using System.Threading.Tasks;  
using Microsoft.Extensions.DependencyInjection;  
using Microsoft.Extensions.Logging;  

public class ThreadTaskMonitor : IHostedService  
{  
    private readonly ConcurrentDictionary<string, TaskInfo> _threadTaskList = new ConcurrentDictionary<string, TaskInfo>();  
    private readonly ILogger<ThreadTaskMonitor> _logger;  
    private CancellationTokenSource _cancellationTokenSource;  

    public ThreadTaskMonitor(ILogger<ThreadTaskMonitor> logger)  
    {  
        _logger = logger;  
    }  

    public Task StartAsync(CancellationToken cancellationToken)  
    {  
        _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);  
        InitializeMonitoring(_cancellationTokenSource.Token);  
        SaveDataAsync(_cancellationTokenSource.Token);  
        return Task.CompletedTask;  
    }  

    public Task StopAsync(CancellationToken cancellationToken)  
    {  
        _cancellationTokenSource.Cancel();  
        return Task.CompletedTask;  
    }  

    public bool AddThreadTask(string taskName, Action action, int milliSeconds = 10)  
    {  
        if (_threadTaskList.ContainsKey(taskName))  
        {  
            _logger.LogError($"Task with name {taskName} already exists!");  
            return false;  
        }  

        var taskInfo = new TaskInfo(taskName)  
        {  
            ActionFunction = action,  
            Task = Task.Run(async () =>  
            {  
                await Task.Delay(milliSeconds);  
                action?.Invoke();  
            })  
        };  

        _threadTaskList[taskName] = taskInfo;  
        return true;  
    }  

    private void InitializeMonitoring(CancellationToken cancellationToken)  
    {  
        Task.Run(async () =>  
        {  
            while (!cancellationToken.IsCancellationRequested)  
            {  
                foreach (var info in _threadTaskList.Values)  
                {  
                    if (info.Task.IsFaulted || info.Task.IsCanceled)  
                    {  
                        _logger.LogInformation($"{info.TaskName} is restarting!");  
                        info.Task = Task.Run(info.ActionFunction);  
                    }  
                    info.State = info.Task.Status.ToString();  
                    info.CurrentTime = DateTime.Now;  
                }  
                await Task.Delay(5000, cancellationToken);  
            }  
        }, cancellationToken);  
    }  

    private async Task SaveDataAsync(CancellationToken cancellationToken)  
    {  
        var _serviceScopeFactory = ServiceLocator.Instance.GetRequiredService<IServiceScopeFactory>();  
        var _dataContext = _serviceScopeFactory.CreateScope().ServiceProvider.GetRequiredService<DataContext>();  

        while (!cancellationToken.IsCancellationRequested)  
        {  
            try  
            {  
                var taskInfoAddList = _threadTaskList.Values.Where(t => t.State == null).ToList();  
                var taskInfoUpdateList = _threadTaskList.Values  
                    .Where(t => t.State != null && _dataContext.TaskInfos.Any(dbTask => dbTask.TaskName == t.TaskName))  
                    .ToList();  

                if (taskInfoAddList.Any())  
                    await _dataContext.TaskInfos.AddRangeAsync(taskInfoAddList, cancellationToken);  

                if (taskInfoUpdateList.Any())  
                {  
                    foreach (var task in taskInfoUpdateList)  
                    {  
                        var dbTask = await _dataContext.TaskInfos.FirstOrDefaultAsync(t => t.TaskName == task.TaskName, cancellationToken);  
                        if (dbTask != null)  
                        {  
                            dbTask.State = task.State;  
                            dbTask.CurrentTime = task.CurrentTime;  
                        }  
                    }  
                }  

                await _dataContext.SaveChangesAsync(cancellationToken);  
            }  
            catch (Exception ex)  
            {  
                _logger.LogError($"Error updating task data: {ex.Message}");  
            }  

            await Task.Delay(10000, cancellationToken); // Save data every 10 seconds  
        }  
    }  
}

  

详细分析

  1. 使用 IHostedService

    • 通过实现 IHostedService,类可以在 ASP.NET Core 中作为后台服务运行,确保在应用程序的生命周期内管理任务。
  2. 引入 CancellationTokenSource

    • 允许优雅地停止监控和保存任务,避免无休止的循环。
  3. 使用 ConcurrentDictionary

    • 提高性能并简化任务的查找和管理。
  4. 合并任务添加逻辑:

    • 通过检查 ContainsKey 来避免重复代码,简化 AddThreadTask 方法。
  5. 异步编程:

    • 使用 async/await 使得代码在等待时不会阻塞线程,提高响应能力。
  6. 异常处理的改进:

    • 提供更多上下文信息,并在数据保存时使用 async 方法,确保数据库操作的非阻塞性。

通过这些优化和重构,代码的可读性、可维护性和性能都有显著提升。

 public interface IService
 {
     Task ExecServiceAsync();
 }

public class WorkerHelper : BackgroundService
{
    private readonly ILogger<Worker> _logger;


    private readonly IServiceScopeFactory _serviceScopeFactory;
    public Worker(ILogger<Worker> logger, IServiceScopeFactory serviceScopeFactory)
    {
        _logger = logger;

        _serviceScopeFactory = serviceScopeFactory;
    }


    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var services = _serviceScopeFactory.CreateScope().ServiceProvider.GetServices<IService>();
        foreach (var service in services)
        {
            (service as IService)?.ExecServiceAsync();

        }
    }
}

services.AddHostedService<WorkerHelper>();

以下是对重构后的 ThreadTaskMonitor 类的使用示例,包括详细的代码和解释。这个使用示例将展示如何在一个 ASP.NET Core 应用中集成和使用该类。

使用示例

1. 在 ASP.NET Core 项目中配置服务

首先,我们需要在 ASP.NET Core Web 应用中配置服务,以便能够使用 ThreadTaskMonitor。可以通过修改 Startup.cs 文件来实现。

Startup.cs

using Microsoft.Extensions.DependencyInjection;  
using Microsoft.Extensions.Hosting;  

public class Startup  
{  
    public void ConfigureServices(IServiceCollection services)  
    {  
        services.AddLogging();  // 增加Logging服务  
        services.AddDbContext<DataContext>(options =>  
            options.UseSqlServer("YourConnectionString"));  // 配置Entity Framework数据库上下文  
        
        // 注册ThreadTaskMonitor作为后台服务  
        services.AddSingleton<ThreadTaskMonitor>();  
    }  

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
    {  
        // Your existing middleware setup  
        
        // Start monitoring when the application starts  
        var monitor = app.ApplicationServices.GetRequiredService<ThreadTaskMonitor>();  
        monitor.StartAsync(CancellationToken.None).GetAwaiter().GetResult();  
    }  
}

  

在上面的代码中,我们将 ThreadTaskMonitor 注册为单例服务。应用程序启动时,将会自动启动任务监控。

2. 添加一个控制器

接下来,我们可以创建一个控制器来演示如何添加和管理线程任务。

TaskController.cs

using Microsoft.AspNetCore.Mvc;  

[Route("api/[controller]")]  
[ApiController]  
public class TaskController : ControllerBase  
{  
    private readonly ThreadTaskMonitor _taskMonitor;  

    public TaskController(ThreadTaskMonitor taskMonitor)  
    {  
        _taskMonitor = taskMonitor;  
    }  

    /// <summary>  
    /// 添加一个新的任务  
    /// </summary>  
    [HttpPost("add")]  
    public IActionResult AddTask(string taskName, int delaySeconds)  
    {  
        bool isSuccess = _taskMonitor.AddThreadTask(taskName, () =>  
        {  
            Console.WriteLine($"{taskName}执行中...");  
            // 模拟任务执行,例如处理一些逻辑  
        }, delaySeconds * 1000); // 转换为毫秒  

        if (isSuccess)  
            return Ok($"Task '{taskName}' added successfully.");  
        else  
            return BadRequest($"Task '{taskName}' already exists.");  
    }  
    
    /// <summary>  
    /// 显示当前所有任务状态  
    /// </summary>  
    [HttpGet("status")]  
    public IActionResult GetTasksStatus()  
    {  
        // 这里可以返回任务状态,或者可以返回一个简化的数据模型  
        return Ok(_taskMonitor.GetCurrentTasks());  
    }  
}

  

在这个控制器中,我们定义了两个端点:

  • AddTask:可以添加新的任务,并指定延迟时间。
  • GetTasksStatus:获取当前所有任务的状态。

3. 任务信息类 TaskInfo

确保定义 TaskInfo 类,它应该包含任务的状态和其他需要的信息。下面是一个基本的 TaskInfo 类的示例:

TaskInfo.cs

using System;  

public class TaskInfo  
{  
    public string TaskName { get; set; }  
    public Action ActionFunction { get; set; }  
    public Task Task { get; set; }  
    public string State { get; set; }  
    public DateTime CurrentTime { get; set; }  

    public TaskInfo(string taskName)  
    {  
        TaskName = taskName;  
        State = "Created";  
        CurrentTime = DateTime.Now;  
    }  
}

/// <summary>
/// 表示线程任务信息类
/// </summary>
[Serializable]
[Table("taskinfo")]
public class TaskInfo: TopBasePoco
{
    public TaskInfo() { }

    public TaskInfo(string taskName)
    {
        ID = Guid.NewGuid().ToString("N");
        TaskName = taskName;
        CurrentTime = DateTime.Now;
    }


    /// <summary>
    /// 表示执行的线程
    /// </summary>
    [NotMapped]
    public Task Task { get; set; }

    /// <summary>
    /// 线程Id
    /// </summary>
    [Display(Name = "线程Id")]
    [Key]
    [Column("TaskId")]
    public new string ID { get; set; }

    /// <summary>
    /// 线程名称
    /// </summary>
    [Display(Name = "线程名称")]
    [StringLength(255, ErrorMessage = "{0}最多输入{1}个字符")]
    public string TaskName { get; set; }

    /// <summary>
    /// 线程执行状态
    /// </summary>
    [StringLength(30,ErrorMessage="{0}最多输入{1}个字符")]
    [Display(Name = "执行状态")]
    public string State { get; set; }

    /// <summary>
    /// 当前时间
    /// </summary>
    [Display(Name = "当前时间")]
    public DateTime CurrentTime { get; set; }

    [NotMapped]
    public Action ActionFunction { get; set; }
}

  

4. 运行和测试应用程序

  1. 启动您的 ASP.NET Core 应用程序。
  2. 通过 Postman、cURL 或浏览器访问以下 URL 添加任务:
    • 添加任务:

      POST http://localhost:5000/api/task/add?taskName=MyTask1&delaySeconds=5
      

       

    • 获取任务状态:

  

GET http://localhost:5000/api/task/status

  

将会看到响应中返回已添加的任务以及它们的状态,例如“执行中”“已完成”等。

详细描述过程

  1. Service Configuration:
    通过将 ThreadTaskMonitor 注册为 Singleton 服务,我们确保在整个应用生命周期内仅有一个实例。这使得后台任务监控在应用的不同组件中都是共享和可访问的。

  2. Controller for Task Management:
    TaskController 能够响应 HTTP 请求,并将任务调度逻辑暴露给外部。通过 POST 请求,可以动态添加任务,同时通过 GET 请求查看当前任务的状态。

  3. Task Execution:
    每当添加任务时,ThreadTaskMonitor 会立即调度相应的动作,并在指定的延迟之后执行。任务的执行状态会被自动监控,并可以在状态列表中获得反馈。

总结

这种使用示例展示了 ThreadTaskMonitor 的集成和利用,能够动态添加任务并监控其状态。我们强调了异步编程的使用、服务注册、以及 API 设计,使这个系统不仅高效而且易维护。这种方式相对灵活,适合在多种业务场景中使用。

当然,可以将 IHostedService 改成 BackgroundService。使用 BackgroundService 是更现代的做法,因为它提供了一种更简洁的方式来处理后台任务,特别是在 ASP.NET Core 应用中。

修改后的 ThreadTaskMonitor 类

我们将 ThreadTaskMonitor 类继承自 BackgroundService,并重构相应的方法。以下是更新后的代码:

using System;  
using System.Collections.Concurrent;  
using System.Linq;  
using System.Threading;  
using System.Threading.Tasks;  
using Microsoft.Extensions.DependencyInjection;  
using Microsoft.Extensions.Hosting;  
using Microsoft.Extensions.Logging;  

public class ThreadTaskMonitor : BackgroundService  
{  
    private readonly ConcurrentDictionary<string, TaskInfo> _threadTaskList = new ConcurrentDictionary<string, TaskInfo>();  
    private readonly IServiceScopeFactory _serviceScopeFactory;  
    private readonly ILogger<ThreadTaskMonitor> _logger;  

    public ThreadTaskMonitor(IServiceScopeFactory serviceScopeFactory, ILogger<ThreadTaskMonitor> logger)  
    {  
        _serviceScopeFactory = serviceScopeFactory;  
        _logger = logger;  
    }  

    public bool AddThreadTask(string taskName, Action action, int milliSeconds = 10)  
    {  
        if (_threadTaskList.ContainsKey(taskName))  
        {  
            _logger.LogError($"Task with name {taskName} already exists!");  
            return false;  
        }  

        var taskInfo = new TaskInfo(taskName)  
        {  
            ActionFunction = action,  
            Task = Task.Run(async () =>  
            {  
                await Task.Delay(milliSeconds);  
                action?.Invoke();  
            })  
        };  

        _threadTaskList[taskName] = taskInfo;  
        return true;  
    }  

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)  
    {  
        var monitoringTask = MonitorTaskStatus(stoppingToken);  
        var saveDataTask = SaveDataAsync(stoppingToken);  

        await Task.WhenAll(monitoringTask, saveDataTask);  
    }  

    private async Task MonitorTaskStatus(CancellationToken stoppingToken)  
    {  
        while (!stoppingToken.IsCancellationRequested)  
        {  
            foreach (var info in _threadTaskList.Values)  
            {  
                if (info.Task.IsFaulted || info.Task.IsCanceled)  
                {  
                    _logger.LogInformation($"{info.TaskName} is restarting!");  
                    info.Task = Task.Run(info.ActionFunction);  
                }  
                info.State = info.Task.Status.ToString();  
                info.CurrentTime = DateTime.Now;  
            }  
            await Task.Delay(5000, stoppingToken);  
        }  
    }  

    private async Task SaveDataAsync(CancellationToken stoppingToken)  
    {  
        while (!stoppingToken.IsCancellationRequested)  
        {  
            using (var scope = _serviceScopeFactory.CreateScope())  
            {  
                var _dataContext = scope.ServiceProvider.GetRequiredService<DataContext>();  

                try  
                {  
                    var taskInfoAddList = _threadTaskList.Values  
                        .Where(t => t.State == null).ToList();  
                    var taskInfoUpdateList = _threadTaskList.Values  
                        .Where(t => t.State != null && _dataContext.TaskInfos.Any(dbTask => dbTask.TaskName == t.TaskName))  
                        .ToList();  

                    if (taskInfoAddList.Any())  
                        await _dataContext.TaskInfos.AddRangeAsync(taskInfoAddList, stoppingToken);  

                    if (taskInfoUpdateList.Any())  
                    {  
                        foreach (var task in taskInfoUpdateList)  
                        {  
                            var dbTask = await _dataContext.TaskInfos.FirstOrDefaultAsync(t => t.TaskName == task.TaskName, stoppingToken);  
                            if (dbTask != null)  
                            {  
                                dbTask.State = task.State;  
                                dbTask.CurrentTime = task.CurrentTime;  
                            }  
                        }  
                    }  

                    await _dataContext.SaveChangesAsync(stoppingToken);  
                }  
                catch (Exception ex)  
                {  
                    _logger.LogError($"Error updating task data: {ex.Message}");  
                }  
            }  
            await Task.Delay(10000, stoppingToken); // 每10秒保存一次数据  
        }  
    }  
}

  

详细修改分析

1. 继承 BackgroundService

public class ThreadTaskMonitor : BackgroundService

通过继承 BackgroundService,我们利用它提供的便利结构来简化后台任务的执行逻辑和管理细节。

2. 重写 ExecuteAsync 方法

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var monitoringTask = MonitorTaskStatus(stoppingToken);
var saveDataTask = SaveDataAsync(stoppingToken);

await Task.WhenAll(monitoringTask, saveDataTask);
}

ExecuteAsync 方法是 BackgroundService 必须实现的一个方法,它在服务启动时自动调用。我们在其中启动监控和保存数据的任务,并等待两者完成。

3. 任务监控方法

private async Task MonitorTaskStatus(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { // ... } }

这个方法循环检查所有任务的状态。如果任务被标记为 Faulted 或 Canceled,则重新启动该任务。整个过程使用 await Task.Delay() 来避免阻塞。

4. 数据保存方法

private async Task SaveDataAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
// ...
}
await Task.Delay(10000, stoppingToken); // 每10秒保存一次数据
}
}

同样,这个方法在后台持续运行,并定期通过 Entity Framework 将线程状态更新到数据库中。使用 CancellationToken 确保可以干净地停止数据保存操作。

更新使用示例

1. 服务注册

在 Startup.cs 中,改为注册 ThreadTaskMonitor 类:

public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(); // 增加Logging服务
services.AddDbContext<DataContext>(options =>
options.UseSqlServer("YourConnectionString")); // 配置Entity Framework数据库上下文

// 注册ThreadTaskMonitor作为后台服务
services.AddHostedService<ThreadTaskMonitor>();
}

2. 控制器和任务的管理

控制器部分无须任何修改,可以保留之前的代码。

总结

通过将 ThreadTaskMonitor 类改为继承自 BackgroundService,我们使代码更加简洁,并利用了 BackgroundService 为后台服务提供的基础结构。这种方式不仅提高了可读性,还确保了任务的可靠性和可维护性,可以适应更加复杂的应用场景。整体服务设置更加符合现代 ASP.NET Core 应用的最佳实践。

  

  

posted on 2024-12-16 08:29  HackerVirus  阅读(8)  评论(0编辑  收藏  举报