• .NET 6.0 Web API Hangfire


    Hangfire 文档 
    Hangfire GitHub使用示例源码 
    在线Cron表达式生成器 

    ● Hangfire允许您以非常简单但可靠的方式在请求管道之外启动方法调用。 这种 后台线程 中执行方法的行为称为 后台任务。
    ● 它是由:客户端、作业存储、服务端 组成的。
    ● Hangfire可以在 ASP.NET Web应用程序 、非ASP.NET Web应用程序、控制台应用程序 或 Windows服务 中使用。
    ● 可以使用Hangfire创建任何类型的后台作业: fire-and-forget (自助调用), delayed (在一段时间后执行调用)、 recurring (按小时,每天执行方法等)
    ● Hangfire将后台任务及相关的其他信息保存到持久库,SQL Server,MySql,Redis,MemoryStorage


    Fire-and-Forget Jobs:仅执行一次,即发即弃作业只执行一次,而且几乎在创建后立即执行。
    Delayed Jobs:延迟的工作,延迟的作业也只执行一次,但在一定的时间间隔后不会立即执行。
    Recurring Jobs:经常性工作,重复作业在指定的CRON计划中多次触发。
    Continuations:延续,当其父作业完成时,将执行连续操作。
    Batches:批量,批处理是一组以原子方式创建的后台作业,并被视为单个实体。
    Batch Continuations:当父批次中的所有后台作业完成时,将激发批次延续。

    1、管理 NuGet 程序包
    Hangfire.AspNetCore
    Hangfire.SqlServer
    Hangfire.MySql
    Hangfire.MemoryStorage
    Hangfire.MySqlStorage
    Hangfire.PostgreSql

    2、Program.cs

    1. using Hangfire;
    2. using Hangfire.MemoryStorage;
    3. using Hangfire.Redis.StackExchange;
    4. using Microsoft.AspNetCore.Builder;
    5. using Microsoft.AspNetCore.Hosting.Server;
    6. using Microsoft.Extensions.Configuration;
    7. var builder = WebApplication.CreateBuilder(args);
    8. var Configuration = builder.Configuration;
    9. // Add services to the container.
    10. #region Add Hangfire services.
    11. // MemoryStorage
    12. builder.Services.AddHangfire(configuration => configuration.UseMemoryStorage());
    13. //builder.Services.AddHangfire(configuration => configuration.UseStorage(new MemoryStorage()));
    14. // Redis
    15. //builder.Services.AddHangfire(x =>
    16. //{
    17. // RedisStorageOptions options = new RedisStorageOptions()
    18. // {
    19. // Prefix = "hangfire:", //键前缀
    20. //    };
    21. // x.UseRedisStorage(Configuration.GetValue("ConnectionStrings:Redis:ConnectionString"), options);
    22. //});
    23. // SqlServer 方式1
    24. //builder.Services.AddHangfire(configuration => configuration.UseSqlServerStorage(config.GetConnectionString("HangfireConnection")));
    25. // SqlServer 方式2
    26. //builder.Services.AddHangfire(configuration => configuration
    27. // .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) // 设置数据兼容级别
    28. // .UseSimpleAssemblyNameTypeSerializer() // 使用简单程序集名称类型序列化程序
    29. // .UseRecommendedSerializerSettings() // 使用推荐的序列化设置
    30. // .UseSqlServerStorage(config.GetValue("ConnectionStrings:BaseDb:ConnectionString"), new SqlServerStorageOptions //数据库设置
    31. // //.UseSqlServerStorage(config.GetConnectionString("HangfireConnection"), new SqlServerStorageOptions
    32. // {
    33. // TransactionIsolationLevel = IsolationLevel.ReadCommitted, // 事务隔离级别。默认值为读提交。
    34. // TransactionTimeout = TimeSpan.FromMinutes(1), // 事务超时。默认为1分钟
    35. // JobExpirationCheckInterval = TimeSpan.FromHours(1), // 作业过期检查间隔(管理过期记录)。默认为1小时
    36. // CountersAggregateInterval = TimeSpan.FromMinutes(5), // 间隔到聚合计数器。默认为5分钟
    37. // PrepareSchemaIfNecessary = true, // 如果设置为true,则创建数据库表。默认值为true
    38. // CommandBatchMaxTimeout = TimeSpan.FromMinutes(5), // 命令批处理最大超时时间
    39. // SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5), // 滑动超时时间
    40. // QueuePollInterval = TimeSpan.Zero, // 作业队列轮询间隔。默认值为15秒
    41. // UseRecommendedIsolationLevel = true, // 是否使用建议的隔离级别
    42. // DisableGlobalLocks = true, // 是否禁用全局锁,需要迁移到模式7
    43. // DashboardJobListLimit = 50000, // 仪表板作业列表上限。默认值为50000
    44. // }));
    45. // Add the processing server as IHostedService
    46. builder.Services.AddHangfireServer();
    47. #endregion
    48. builder.Services.AddScoped();
    49. builder.Services.AddControllers();
    50. var app = builder.Build();
    51. // Configure the HTTP request pipeline.
    52. //Hangfire 仪表盘
    53. //访问地址 http://localhost:5000/hangfire
    54. app.UseHangfireDashboard();
    55. app.UseAuthorization();
    56. #region Hangfire
    57. // 基于队列的任务处理
    58. var jobId = BackgroundJob.Enqueue(() => Console.WriteLine("即时任务!"));
    59. // 延迟任务执行
    60. var jobId2 = BackgroundJob.Schedule(() => Console.WriteLine("延迟任务!"), TimeSpan.FromMilliseconds(10));
    61. // 循环任务执行,最小单位是分钟,可以自定义复杂模式
    62. //RecurringJob.AddOrUpdate("myrecurringjob", () => Console.WriteLine("重复任务!"), Cron.Minutely);
    63. RecurringJob.AddOrUpdate("myrecurringjob", () => Console.Write("重复任务,每1分钟执行任务"), "0 0/1 * * * ?");
    64. RecurringJob.AddOrUpdate("SendEmail", x => x.SendEmail("test@example.com", "Subject", "Body"), Cron.MinuteInterval(1));
    65. RecurringJob.AddOrUpdate("User", u => u.Get(), Cron.Minutely);
    66. // 延续性任务执行,在第一个任务执行完之后紧接着再次执行另外的任务
    67. BackgroundJob.ContinueJobWith(jobId2, () => Console.WriteLine("jobId2执行完了再继续执行!"));
    68. using (var server = new BackgroundJobServer())
    69. {
    70. BackgroundJob.Enqueue(() => Console.WriteLine("Simple111"));
    71. }
    72. #endregion
    73. app.MapControllers();
    74. #region Hangfire
    75. app.Map("/index", r =>
    76. {
    77. r.Run(async context =>
    78. {
    79. //任务每分钟执行一次
    80. RecurringJob.AddOrUpdate(() => Console.WriteLine($"ASP.NET Core LineZero"), Cron.Minutely());
    81. await context.Response.WriteAsync("ok");
    82. });
    83. });
    84. app.Map("/one", r =>
    85. {
    86. r.Run(context =>
    87. {
    88. //任务执行一次
    89. BackgroundJob.Enqueue(() => Console.WriteLine($"ASP.NET Core One Start LineZero{DateTime.Now}"));
    90. return context.Response.WriteAsync("ok");
    91. });
    92. });
    93. app.Map("/await", r =>
    94. {
    95. r.Run(context =>
    96. {
    97. //任务延时两分钟执行
    98. BackgroundJob.Schedule(() => Console.WriteLine($"ASP.NET Core await LineZero{DateTime.Now}"), TimeSpan.FromMinutes(2));
    99. return context.Response.WriteAsync("ok");
    100. });
    101. });
    102. #endregion
    103. app.Run();

    3、CustomJobController.cs

    1. using Hangfire.Server;
    2. using Hangfire;
    3. using Microsoft.AspNetCore.Http;
    4. using Microsoft.AspNetCore.Mvc;
    5. namespace Web.Controllers
    6. {
    7. [Route("api/[controller]")]
    8. [ApiController]
    9. public class CustomJobController : ControllerBase
    10. {
    11. private readonly ILogger _logger;
    12. private readonly IBackgroundJobClient _backgroundJobClient;
    13. public CustomJobController(ILogger logger, IBackgroundJobClient backgroundJobClient)
    14. {
    15. _logger = logger;
    16. _backgroundJobClient = backgroundJobClient;
    17. }
    18. [HttpGet]
    19. public IActionResult Get()
    20. {
    21. var jobId = _backgroundJobClient.Enqueue(() => FireAndForgetJob(null));
    22. Thread.Sleep(5000);
    23. return Ok($"Job Id: {jobId} completed...");
    24. }
    25. [HttpGet]
    26. public IActionResult Get1()
    27. {
    28. var jobId = BackgroundJob.Schedule(() => Console.WriteLine("This is an example of a delayed job"), TimeSpan.FromDays(1));
    29. return Ok($"Job Id: {jobId} completed...");
    30. }
    31. [HttpGet]
    32. public IActionResult Get2()
    33. {
    34. var jobId = _backgroundJobClient.Enqueue(() => FireAndForgetJob(null));
    35. Thread.Sleep(5000);
    36. return Ok($"Job Id: {jobId} completed...");
    37. }
    38. public Task FireAndForgetJob(PerformContext context)
    39. {
    40. var jobId = context.BackgroundJob.Id;
    41. _logger.LogInformation($"Executing Job Id: {jobId}...");
    42. return Task.CompletedTask;
    43. }
    44. }
    45. }

    4、BackgroundJobService

    1. namespace Web
    2. {
    3. public class BackgroundJobService
    4. {
    5. public void SendEmail(string emailAddress, string subject, string body)
    6. {
    7. // 发送电子邮件
    8. Console.WriteLine(DateTime.Now.ToString() + " " + emailAddress + "\r\n");
    9. }
    10. }
    11. }

    5、IUserService

    1. namespace Web.Services
    2. {
    3. public interface IUserService
    4. {
    5. string Get();
    6. }
    7. public class UserService : IUserService
    8. {
    9. public string Get()
    10. {
    11. DateTime dt = DateTime.Now;
    12. Console.WriteLine(dt.ToString() + "\r\n");
    13. return dt.ToString() + "\r\n";
    14. }
    15. }
    16. }

    6、Cron 表达式
    是一个时间表达式,包含6或7个字段组成,每个字段代表不同的时间单位,前6个字段是必须的,最后一个【年】是可选的,从左到右依次为
    7个字段:秒 分 时 日 月 星期 年
    6个字段:秒 分 时 日 月 星期 (年可为空)
    其中年可为空,不是必须;     

    在大部分使用cron的场景下, - * / ? 这几个常用字符就可以满足我们的需求了。
    【*】:每的意思。在不同的字段上,就代表每秒,每分,每小时等。
    【-】:指定值的范围。比如[1-10],在秒字段里就是每分钟的第1到10秒,在分就是每小时的第1到10分钟,以此类推。
    【,】:指定某几个值。比如[2,4,5],在秒字段里就是每分钟的第2,第4,第5秒,以此类推。
    【/】:指定值的起始和增加幅度。比如[3/5],在秒字段就是每分钟的第3秒开始,每隔5秒生效一次,也就是第3秒、8秒、13秒,以此类推。
    【?】:仅用于【日】和【周】字段。因为在指定某日和周几的时候,这两个值实际上是冲突的,所以需要用【?】标识不生效的字段。比如【0 1 * * * ?】就代表每年每月每日每小时的1分0秒触发任务。这里的周就没有效果了。
    *
    分钟字段,表示程序应该在哪些分钟运行
    星号(*):表示每隔1分钟触发
    逗号(,):用于指定多个分钟,例如【0,15,30,45】表示每小时的0、15、30和45分钟
    中划线(-):用于指定一个时间段,例如:【10-20】表示从10分钟到20分钟
    斜杠(/):用于指定一个时间间隔,例如:【*/5】表示每5分钟
    *
    示例:
    0 0/5 * * * *:每5分钟运行程序
    0 10,20 * * * *:在每个小时的10和20分钟运行程序
    0 10-20/5 * * * *:在每个小时的10到20分钟之间每5分钟运行程序
    *
    小时字段表示程序应该在哪些小时运行
    - 星号(*):表示所有小时
    - 逗号(,):用于指定多个小时,例如:——0,12,18——表示每天的0、12、18点
    - 中划线(-):用于指定一个时间段,例如:——9-17——表示从9点到17点
    - 斜杠(/):用于指定一个时间间隔,例如:——*/2——表示每2小时
    *
    示例:
    0 0 */2 * * *:每2小时运行程序
    0 9-17 * * * *:在每天的9点到17点之间运行程序
    0 0-12/3 * * * *:在每天的0点到12点之间每3小时运行程序
    *
    经典案例:
    "5 * * * * ?"   每分钟的第5秒执行一次
    "30 * * * * ?" 每分钟的第30秒触发任务
    "30 10 * * * ?" 每小时的10分30秒触发任务
    "30 10 1 * * ?" 每天1点10分30秒触发任务
    "30 10 1 20 * ?" 每月20号1点10分30秒触发任务
    "30 10 1 20 10 ? *" 每年10月20号1点10分30秒触发任务
    "30 10 1 20 10 ? 2011" 2011年10月20号1点10分30秒触发任务
    "30 10 1 ? 10 * 2011" 2011年10月每天1点10分30秒触发任务
    "30 10 1 ? 10 SUN 2011" 2011年10月每周日1点10分30秒触发任务
    "15,30,45 * * * * ?" 每15秒,30秒,45秒时触发任务
    "15-45 * * * * ?" 15到45秒内,每秒都触发任务
    "15/5 * * * * ?" 每分钟的每15秒开始触发,每隔5秒触发一次
    "15-30/5 * * * * ?" 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次
    "0 0/3 * * * ?" 每小时的第0分0秒开始,每三分钟触发一次
    "0 15 10 ? * MON-FRI" 星期一到星期五的10点15分0秒触发任务
    "0 15 10 L * ?" 每个月最后一天的10点15分0秒触发任务
    "0 15 10 LW * ?" 每个月最后一个工作日的10点15分0秒触发任务
    "0 15 10 ? * 5L" 每个月最后一个星期四的10点15分0秒触发任务
    "0 15 10 ? * 5#3" 每个月第三周的星期四的10点15分0秒触发任务

    常用cron表达式例子 
    (1)0/2 * * * * ?   表示每2秒 执行任务
    (1)0 0/2 * * * ?    表示每2分钟 执行任务
    (1)0 0 2 1 * ?   表示在每月的1日的凌晨2点调整任务
    (2)0 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业
    (3)0 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作
    (4)0 0 10,14,16 * * ?   每天上午10点,下午2点,4点 
    (5)0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时 
    (6)0 0 12 ? * WED    表示每个星期三中午12点 
    (7)0 0 12 * * ?   每天中午12点触发 
    (8)0 15 10 ? * *    每天上午10:15触发 
    (9)0 15 10 * * ?     每天上午10:15触发 
    (10)0 15 10 * * ?    每天上午10:15触发 
    (11)0 15 10 * * ? 2005    2005年的每天上午10:15触发 
    (12)0 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发 
    (13)0 0/5 14 * * ?    在每天下午2点到下午2:55期间的每5分钟触发 
    (14)0 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 
    (15)0 0-5 14 * * ?    在每天下午2点到下午2:05期间的每1分钟触发 
    (16)0 10,44 14 ? 3 WED    每年三月的星期三的下午2:10和2:44触发 
    (17)0 15 10 ? * MON-FRI    周一至周五的上午10:15触发 
    (18)0 15 10 15 * ?    每月15日上午10:15触发 
    (19)0 15 10 L * ?    每月最后一日的上午10:15触发 
    (20)0 15 10 ? * 6L    每月的最后一个星期五上午10:15触发 
    (21)0 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发 
    (22)0 15 10 ? * 6#3   每月的第三个星期五上午10:15触发
    *
    *
    *

  • 相关阅读:
    MySQL进阶篇2-索引的创建和使用
    外包干了2个月,技术退步明显...
    Python开发运维:PyMongo 连接操作 MongoDB
    UI自动化测试(弹出框,多窗口)
    数据可视化之大数据可视化
    性能测试常见的测试指标
    实验三十二、OCL电路的研究
    Docker基本使用
    ubuntu 20.04 使用systemback自定义系统镜像和系统备份
    180.Hive(二):数据类型,数据库的crud,数据库表的crud,数据的导入导出,分区表,分桶表
  • 原文地址:https://blog.csdn.net/KingCruel/article/details/133889049