最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

.NET6實現分布式定時任務的完整方案

 更新時間:2025年04月20日 10:32:43   作者:碼上有潛  
這篇文章主要為大家詳細介紹了.NET6實現分布式定時任務的完整方案,文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以參考一下

1. 基礎設施層

分布式鎖服務

// IDistributedLockService.cs
public interface IDistributedLockService
{
    ValueTask<IAsyncDisposable?> AcquireLockAsync(string resourceKey, TimeSpan expiryTime);
}

// RedisDistributedLockService.cs
public class RedisDistributedLockService : IDistributedLockService
{
    private readonly IConnectionMultiplexer _redis;
    private readonly ILogger<RedisDistributedLockService> _logger;

    public RedisDistributedLockService(
        IConnectionMultiplexer redis,
        ILogger<RedisDistributedLockService> logger)
    {
        _redis = redis;
        _logger = logger;
    }

    public async ValueTask<IAsyncDisposable?> AcquireLockAsync(string resourceKey, TimeSpan expiryTime)
    {
        var db = _redis.GetDatabase();
        var lockToken = Guid.NewGuid().ToString();
        var lockKey = $"distributed-lock:{resourceKey}";

        try
        {
            var acquired = await db.LockTakeAsync(lockKey, lockToken, expiryTime);
            if (acquired)
            {
                _logger.LogDebug("成功獲取分布式鎖 {LockKey}", lockKey);
                return new RedisLockHandle(db, lockKey, lockToken, _logger);
            }
            
            _logger.LogDebug("無法獲取分布式鎖 {LockKey}", lockKey);
            return null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "獲取分布式鎖 {LockKey} 時發(fā)生錯誤", lockKey);
            throw;
        }
    }

    private sealed class RedisLockHandle : IAsyncDisposable
    {
        private readonly IDatabase _db;
        private readonly string _lockKey;
        private readonly string _lockToken;
        private readonly ILogger _logger;
        private bool _isDisposed;

        public RedisLockHandle(
            IDatabase db,
            string lockKey,
            string lockToken,
            ILogger logger)
        {
            _db = db;
            _lockKey = lockKey;
            _lockToken = lockToken;
            _logger = logger;
        }

        public async ValueTask DisposeAsync()
        {
            if (_isDisposed) return;

            try
            {
                var released = await _db.LockReleaseAsync(_lockKey, _lockToken);
                if (!released)
                {
                    _logger.LogWarning("釋放分布式鎖 {LockKey} 失敗", _lockKey);
                }
                else
                {
                    _logger.LogDebug("成功釋放分布式鎖 {LockKey}", _lockKey);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "釋放分布式鎖 {LockKey} 時發(fā)生錯誤", _lockKey);
            }
            finally
            {
                _isDisposed = true;
            }
        }
    }
}

2. 任務服務層

定時任務服務

// IPollingService.cs
public interface IPollingService
{
    Task ExecutePollingTasksAsync();
    Task ExecuteDailyTaskAsync(int hour);
}

// PollingService.cs
public class PollingService : IPollingService
{
    private readonly IDistributedLockService _lockService;
    private readonly ILogger<PollingService> _logger;

    public PollingService(
        IDistributedLockService lockService,
        ILogger<PollingService> logger)
    {
        _lockService = lockService;
        _logger = logger;
    }

    [DisableConcurrentExecution(timeoutInSeconds: 60 * 30)] // 30分鐘防并發(fā)
    public async Task ExecutePollingTasksAsync()
    {
        await using var lockHandle = await _lockService.AcquireLockAsync(
            "polling-tasks-lock",
            TimeSpan.FromMinutes(25)); // 鎖有效期25分鐘

        if (lockHandle is null)
        {
            _logger.LogInformation("其他節(jié)點正在執(zhí)行輪詢任務,跳過本次執(zhí)行");
            return;
        }

        try
        {
            _logger.LogInformation("開始執(zhí)行輪詢任務 - 節(jié)點: {NodeId}", Environment.MachineName);
            
            // 執(zhí)行所有輪詢任務
            await Task.WhenAll(
                PollingTaskAsync(),
                PollingExpireTaskAsync(),
                PollingExpireDelCharactTaskAsync()
            );
            
            // 觸發(fā)后臺任務
            _ = BackgroundTask.Run(() => PollingDelCharactTaskAsync(), _logger);
            _ = BackgroundTask.Run(() => AutoCheckApiAsync(), _logger);
            _ = BackgroundTask.Run(() => DelLogsAsync(), _logger);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "執(zhí)行輪詢任務時發(fā)生錯誤");
            throw;
        }
    }

    [DisableConcurrentExecution(timeoutInSeconds: 60 * 60)] // 1小時防并發(fā)
    public async Task ExecuteDailyTaskAsync(int hour)
    {
        var lockKey = $"daily-task-{hour}:{DateTime.UtcNow:yyyyMMdd}";
        
        await using var lockHandle = await _lockService.AcquireLockAsync(
            lockKey,
            TimeSpan.FromMinutes(55)); // 鎖有效期55分鐘

        if (lockHandle is null)
        {
            _logger.LogInformation("其他節(jié)點已執(zhí)行今日 {Hour} 點任務", hour);
            return;
        }

        try
        {
            _logger.LogInformation("開始執(zhí)行 {Hour} 點任務 - 節(jié)點: {NodeId}", 
                hour, Environment.MachineName);
            
            if (hour == 21)
            {
                await ExecuteNightlyMaintenanceAsync();
            }
            else if (hour == 4)
            {
                await ExecuteEarlyMorningTasksAsync();
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "執(zhí)行 {Hour} 點任務時發(fā)生錯誤", hour);
            throw;
        }
    }

    // 具體任務實現方法
    private async Task PollingTaskAsync()
    {
        // 實現游戲角色啟動/關閉邏輯
    }
    
    private async Task ExecuteNightlyMaintenanceAsync()
    {
        // 21點特殊任務邏輯
    }
    
    // 其他方法...
}

// BackgroundTask.cs (安全運行后臺任務)
public static class BackgroundTask
{
    public static Task Run(Func<Task> task, ILogger logger)
    {
        return Task.Run(async () =>
        {
            try
            {
                await task();
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "后臺任務執(zhí)行失敗");
            }
        });
    }
}

3. 任務調度配置層

任務初始化器

// RecurringJobInitializer.cs
public class RecurringJobInitializer : IHostedService
{
    private readonly IRecurringJobManager _jobManager;
    private readonly IServiceProvider _services;
    private readonly ILogger<RecurringJobInitializer> _logger;

    public RecurringJobInitializer(
        IRecurringJobManager jobManager,
        IServiceProvider services,
        ILogger<RecurringJobInitializer> logger)
    {
        _jobManager = jobManager;
        _services = services;
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        try
        {
            using var scope = _services.CreateScope();
            var pollingService = scope.ServiceProvider.GetRequiredService<IPollingService>();
            
            // 每30分鐘執(zhí)行的任務
            _jobManager.AddOrUpdate<IPollingService>(
                "polling-tasks-30min",
                s => s.ExecutePollingTasksAsync(),
                "*/30 * * * *");
            
            // 每天21:00執(zhí)行的任務
            _jobManager.AddOrUpdate<IPollingService>(
                "daily-task-21:00",
                s => s.ExecuteDailyTaskAsync(21),
                "0 21 * * *");
            
            // 每天04:00執(zhí)行的任務
            _jobManager.AddOrUpdate<IPollingService>(
                "daily-task-04:00",
                s => s.ExecuteDailyTaskAsync(4),
                "0 4 * * *");

            _logger.LogInformation("周期性任務初始化完成");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "初始化周期性任務失敗");
            throw;
        }

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

4. 應用啟動配置

Program.cs

var builder = WebApplication.CreateBuilder(args);

// 添加Redis
builder.Services.AddSingleton<IConnectionMultiplexer>(sp => 
    ConnectionMultiplexer.Connect(builder.Configuration.GetConnectionString("Redis")));

// 配置Hangfire
builder.Services.AddHangfire(config =>
{
    config.UseRedisStorage(
        builder.Configuration.GetConnectionString("Redis"),
        new RedisStorageOptions
        {
            Prefix = "hangfire:",
            Db = 1 // 使用單獨的Redis數據庫
        });
    
    config.UseColouredConsoleLogProvider();
});

builder.Services.AddHangfireServer(options =>
{
    options.ServerName = $"{Environment.MachineName}:{Guid.NewGuid():N}";
    options.WorkerCount = 1;
    options.Queues = new[] { "default", "critical" };
});

// 注冊服務
builder.Services.AddSingleton<IDistributedLockService, RedisDistributedLockService>();
builder.Services.AddScoped<IPollingService, PollingService>();
builder.Services.AddHostedService<RecurringJobInitializer>();

var app = builder.Build();

// 配置Hangfire儀表盤
app.UseHangfireDashboard("/jobs", new DashboardOptions
{
    DashboardTitle = "任務調度中心",
    Authorization = new[] { new HangfireDashboardAuthorizationFilter() },
    StatsPollingInterval = 60_000 // 60秒刷新一次
});

app.Run();

// Hangfire儀表盤授權過濾器
public class HangfireDashboardAuthorizationFilter : IDashboardAuthorizationFilter
{
    public bool Authorize(DashboardContext context)
    {
        var httpContext = context.GetHttpContext();
        return httpContext.User.Identity?.IsAuthenticated == true;
    }
}

5. appsettings.json 配置

{
  "ConnectionStrings": {
    "Redis": "localhost:6379,allowAdmin=true",
    "Hangfire": "Server=(localdb)\\mssqllocaldb;Database=Hangfire;Trusted_Connection=True;"
  },
  "Hangfire": {
    "WorkerCount": 1,
    "SchedulePollingInterval": 5000
  }
}

關鍵設計說明

1.分布式鎖:

  • 使用Redis RedLock算法實現
  • 自動處理鎖的獲取和釋放
  • 包含完善的錯誤處理和日志記錄

2.任務隔離:

  • 使用Hangfire的[DisableConcurrentExecution]防止同一任務重復執(zhí)行
  • 分布式鎖確??绻?jié)點唯一執(zhí)行

3.錯誤處理:

  • 所有關鍵操作都有try-catch和日志記錄
  • 后臺任務使用安全包裝器執(zhí)行

4.可觀測性:

  • 詳細的日志記錄
  • Hangfire儀表盤監(jiān)控

5.擴展性:

  • 可以輕松添加新任務
  • 支持動態(tài)調整調度策略

這個實現方案完全符合.NET 6的最佳實踐,支持分布式部署,確保任務在集群環(huán)境中安全可靠地執(zhí)行。

到此這篇關于.NET6實現分布式定時任務的完整方案的文章就介紹到這了,更多相關.NET6分布式定時任務內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C# 根據表格偶數、奇數加載不同顏色

    C# 根據表格偶數、奇數加載不同顏色

    這篇文章主要介紹了C# 根據表格偶數、奇數加載不同顏色,需要的朋友可以參考下
    2017-09-09
  • C#實現狀態(tài)欄提示信息功能的示例

    C#實現狀態(tài)欄提示信息功能的示例

    今天小編就為大家分享一篇C#實現狀態(tài)欄提示信息功能的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • C# DataTable使用方法詳解

    C# DataTable使用方法詳解

    這篇文章主要為大家詳細介紹了C# DataTable的使用方法,感興趣的小伙伴們可以參考一下
    2016-02-02
  • C#實現變量交換、斐波那契數列、質數、回文方法合集

    C#實現變量交換、斐波那契數列、質數、回文方法合集

    這篇文章介紹了C#實現變量交換、斐波那契數列、質數、回文的方法合集,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • 通過C#實現在Excel單元格中寫入文本、或數值

    通過C#實現在Excel單元格中寫入文本、或數值

    在商業(yè)、學術和日常生活中,Excel 的使用極為普遍,本文將詳細介紹如何使用免費.NET庫將數據寫入到 Excel 中,包括文本、數值、數組、和DataTable數據的輸入,需要的朋友可以參考下
    2024-07-07
  • C#?Winform設置登錄跳轉的四種方式總結

    C#?Winform設置登錄跳轉的四種方式總結

    這篇文章主要為大家詳細介紹了C# Winform設置登錄跳轉的四種方式,所有代碼可直接復制到項目中使用,同時說明各方式的核心差異和注意事項
    2026-02-02
  • 使用C#語言實現的查詢條件界面展開和收起功能

    使用C#語言實現的查詢條件界面展開和收起功能

    這篇文章主要介紹了使用C#語言實現的查詢條件界面展開和收起功能的完美解決方案,需要的朋友可以參考下
    2016-11-11
  • 完成OSS.Http底層HttpClient重構封裝 支持標準庫

    完成OSS.Http底層HttpClient重構封裝 支持標準庫

    OSS.Http項目對于.Net Standard標準庫的支持已經遷移完畢,OSS開源系列兩個最底層的類庫已經具備跨運行時支持的能力。本篇文章主要包含 1. HttpClient的介紹,2. 重構的思路, 3. 容易遇到的問題。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • 英語單詞state與status的區(qū)別

    英語單詞state與status的區(qū)別

    state傾向于condition,是一種延續(xù)性的狀態(tài)。status常用于描述一個過程中的某階段(phase),類似于C語言中枚舉型變量某一個固定的值,這個值屬于一個已知的集合。這篇文章主要介紹了英語單詞state與status的區(qū)別,需要的朋友可以參考下
    2016-11-11
  • c# 連接access數據庫config配置

    c# 連接access數據庫config配置

    c# 連接access數據庫config配置,需要的朋友可以參考一下
    2013-02-02

最新評論

广德县| 兴隆县| 齐齐哈尔市| 宜川县| 阿合奇县| 诸城市| 临泽县| 岢岚县| 社旗县| 屏山县| 毕节市| 宁南县| 师宗县| 宁南县| 乌拉特中旗| 佛山市| 岱山县| 嫩江县| 太保市| 鄂州市| 正蓝旗| 台东县| 阿合奇县| 红原县| 海林市| 宜川县| 类乌齐县| 越西县| 北海市| 漳平市| 明光市| 酉阳| 巴彦淖尔市| 甘南县| 宝山区| 昌都县| 即墨市| 枝江市| 太保市| 武义县| 息烽县|