.Net Core之后台任務


.Net Core之后台任務

.Net Core自帶的后台任務可以滿足基礎需求,而更高級的用法則需要自己實現或使用第三方庫,比如Hangfire

自帶后台任務(IHostedService)

一次性,周期性,任務隊列都可以通過IHostedService快速實現,微軟官方文檔已經做了很詳細的說明,我這里就放出一個周期任務的例子

    /// <summary>
    /// 定時任務
    /// </summary>
    public class TimedHostedService : IHostedService, IDisposable
    {
        private int executionCount = 0;
        private readonly ILogger<TimedHostedService> _logger;
        private Timer _timer;

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

        public Task StartAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Timed Hosted Service running.");

            //周期:一小時
            _timer = new Timer(DoWork, null, TimeSpan.Zero, 
                TimeSpan.FromHours(1));

            return Task.CompletedTask;
        }

        private void DoWork(object state)
        {
            var count = Interlocked.Increment(ref executionCount);
            
            //邏輯代碼
            
            _logger.LogInformation(
                "Timed Hosted Service is working. Count: {Count}", count);
        }

        public Task StopAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Timed Hosted Service is stopping.");

            _timer?.Change(Timeout.Infinite, 0);

            return Task.CompletedTask;
        }

        public void Dispose()
        {
            _timer?.Dispose();
        }
    }

Hangfire

Hangfire在很多方面都做得很好,比起Quartz.NET,有web管理頁面,集成和管理更方便,這里也不對兩者進行比較

  • 集成

    這里使用SqlServer做持久化

//ConfigureServices里注入
services.AddHangfire(configuration => configuration
    .SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
    .UseSimpleAssemblyNameTypeSerializer()
    .UseRecommendedSerializerSettings()
    .UseSqlServerStorage(connectionString, new SqlServerStorageOptions
    {
        CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
        SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
        QueuePollInterval = TimeSpan.Zero,
        UseRecommendedIsolationLevel = true,
        UsePageLocksOnDequeue = true,
        DisableGlobalLocks = true
    }));
//Configure里啟用
//Hangfire管理頁面
app.UseHangfireDashboard("/hangfire", new DashboardOptions()
{
    Authorization = new[] { new HangFireAuthorizationFilter() }
});
app.UseHangfireServer();
  • 任務定義

    使用Hangfire定義后台任務是完全解耦的,只需要把對應的任務方法提供出來即可,這里注入IServiceProvider,方便復雜任務的處理

/// <summary>
/// 定時任務
/// </summary>
public class JobService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ILogger _logger;

    public JobService(IServiceProvider serviceProvider, ILogger<JobService> logger)
    {
        _serviceProvider = serviceProvider;
        _logger = logger;
    }
    
    public async Task DoWork()
    {
        _logger.LogInformation($"Start DoWork");
        using (var scope = _serviceProvider.CreateScope())
        {
            //邏輯代碼
        }
        _logger.LogInformation($"End DoWork");
    }
}
services.AddSingleton<JobService>();
  • 任務使用

    使用Hangfire觸發后台任務很簡單,只需要在使用的地方觸發就可以

//后台任務:立刻執行
BackgroundJob.Enqueue(() => _jobService.DoWork());
//計划任務:1分鍾后執行
BackgroundJob.Schedule(() => _jobService.DoWork(), TimeSpan.FromMinutes(1));
//周期任務:每小時執行一次
RecurringJob.AddOrUpdate(id, () => _jobService.DoWork(), Cron.Hourly);
//可以通過任務id取消任務
RecurringJob.RemoveIfExists(id);
  • 任務管理

    Hangfire提供了web管理頁面,可以查看,操作任務,同樣提供了接口來自己查詢任務數據。

    我們也可以自己獲取數據,定制自己的web管理頁面,這里以周期任務為例,做一些基礎查詢

    public JobInfo GetJobInfo(string id)
    {
        //通過任務id獲取信息
        var connection = JobStorage.Current.GetConnection();
        var jobData = connection.GetAllEntriesFromHash($"recurring-job:{id}");
        if (!jobData.IsNullOrEmpty())
        {
            result.Running = true;
            if (jobData.TryGetValue("Cron", out var cron))
            {
                result.Cron = cron;
            }
    
            if (jobData.TryGetValue("NextExecution", out var nextExecution))
            {
                result.NextExecution = DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(nextExecution))
                    .LocalDateTime;
            }
    
            if (jobData.TryGetValue("LastExecution", out var lastExecution))
            {
                result.LastExecution = DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(lastExecution))
                    .LocalDateTime;
            }
        }
    
        return result;
    }
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM