龚冰 發表於 2025-3-27 14:41:00

Longbow.Tasks 实战—任务持久化

<p>原文地址&nbsp;https://www.cnblogs.com/ysmc/p/18795934</p>
<p>  之前写过一个文章,是介绍Longbow.Tasks这个定时任务调度库的,然后不少小伙伴问过我,怎么东西怎么用,也怪我,在那篇文章结尾我讲过要出实战的,后来抛之脑后了,实在惭愧。</p>
<p>  简单讲下这个库的情况,Longbow.Tasks 于Gitee 上开源,这个是开源地址:https://gitee.com/Longbow/Longbow.Tasks ,最主要的是改库支持&nbsp;&nbsp;NETFramework 4.5+ 与 NETCore 2.0+。<br></p>
<p>  先来回顾一下怎么使用这个库:</p>
<h3>初始化</h3>
<p>.NET Core 中,包括 .NET 5&nbsp;.NET 6&nbsp;.NET 7.....需要注入服务</p>
<div class="cnblogs_code">
<pre>builder.Services.AddTaskServices();</pre>
</div>
<p>NETFramework 4.5+</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 程序入口调用</span>
TaskServicesManager.Init();</pre>
</div>
<h3>使用例子</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">立即执行,仅执行一次</span>
<span style="color: rgba(0, 128, 128, 1)"> 2</span> TaskServicesManager.GetOrAdd&lt;TasksDemo&gt;(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">任务唯一标识</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>
<span style="color: rgba(0, 128, 128, 1)"> 4</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">周期性任务 (1 分钟后间隔 5 秒执行2次任务)</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span> <span style="color: rgba(0, 0, 255, 1)">var</span> trigger = TriggerBuilder.Default.WithInterval(TimeSpan.FromSeconds(<span style="color: rgba(128, 0, 128, 1)">5</span>)).WithRepeatCount(<span style="color: rgba(128, 0, 128, 1)">2</span>).WithStartTime(DateTimeOffset.Now.AddMinutes(<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)).Build();
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span>
<span style="color: rgba(0, 128, 128, 1)"> 7</span> TaskServicesManager.GetOrAdd&lt;TasksDemo&gt;(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">任务唯一标识</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, trigger);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">支持cron表达式,间隔 5 秒循环执行任务</span>
<span style="color: rgba(0, 128, 128, 1)">10</span> TaskServicesManager.GetOrAdd&lt;TasksDemo&gt;(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">任务唯一标识</span><span style="color: rgba(128, 0, 0, 1)">"</span>, TriggerBuilder.Build(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*/5 * * * * *</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">));
</span><span style="color: rgba(0, 128, 128, 1)">11</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这里重点关注,可以让你的任务接收 serviceProvider 参数,这样就可以使用注入的服务了</span>
<span style="color: rgba(0, 128, 128, 1)">13</span> TaskServicesManager.GetOrAdd(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">任务唯一标识</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">async</span> (serviceProvider, token) =&gt;
<span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)">15</span>   System.Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">任务唯一标识</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">16</span>   <span style="color: rgba(0, 0, 255, 1)">await</span> Task.Delay(<span style="color: rgba(128, 0, 128, 1)">1000</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">17</span> }, TriggerBuilder.Build(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*/5 12 * * * *</span><span style="color: rgba(128, 0, 0, 1)">"</span>));</pre>
</div>
<h3>持久化</h3>
<p>  这里我使用 .NET 8 为例子,主要使用的是&nbsp;依赖项注入-键控服务</p>
<p>1、我们先定义一个任务接口</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">interface</span><span style="color: rgba(0, 0, 0, 1)"> ITestService
{
    Task Run(IServiceProvider serviceProvider);
}</span></pre>
</div>
<p>2、注册几个任务</p>
<div class="cnblogs_code">
<p>builder.Services.AddKeyedTransient&lt;ITestService, Test1Service&gt;("Test1");<br>builder.Services.AddKeyedTransient&lt;ITestService, Test2Service&gt;("Test2");<br>builder.Services.AddKeyedTransient&lt;ITestService, Test3Service&gt;("Test3");</p>

</div>
<p>3、写一个&nbsp;IHostedService,用于定时任务的添加</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> TestHostedService : IHostedService
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span> <span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 128, 128, 1)"> 3</span>   <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">readonly</span><span style="color: rgba(0, 0, 0, 1)"> IServiceProvider _serviceProvider;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>
<span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> TestHostedService(IServiceProvider serviceProvider)
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>         _serviceProvider =<span style="color: rgba(0, 0, 0, 1)"> serviceProvider;
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span>
<span style="color: rgba(0, 128, 128, 1)">10</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">11</span>   <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> 假设这里是从数据库中读取的定时任务
</span><span style="color: rgba(0, 128, 128, 1)">12</span>   <span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)">&lt;/summary&gt;</span>
<span style="color: rgba(0, 128, 128, 1)">13</span>   <span style="color: rgba(0, 0, 255, 1)">public</span> Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>&gt; Servers = <span style="color: rgba(0, 0, 255, 1)">new</span> Dictionary&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>&gt;<span style="color: rgba(0, 0, 0, 1)">()
</span><span style="color: rgba(0, 128, 128, 1)">14</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">15</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">key为服务名称,value为cron表达式</span>
<span style="color: rgba(0, 128, 128, 1)">16</span>         [<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Task1</span><span style="color: rgba(128, 0, 0, 1)">"</span>] = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*/5 12 * * * *</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">17</span>         [<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Task2</span><span style="color: rgba(128, 0, 0, 1)">"</span>] = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*/10 12 * * * *</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">18</span>         [<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Task3</span><span style="color: rgba(128, 0, 0, 1)">"</span>] = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">*/15 12 * * * *</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 0, 1)">    };
</span><span style="color: rgba(0, 128, 128, 1)">20</span>
<span style="color: rgba(0, 128, 128, 1)">21</span>   <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span><span style="color: rgba(0, 0, 0, 1)"> Task StartAsync(CancellationToken cancellationToken)
</span><span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">23</span>         <span style="color: rgba(0, 0, 255, 1)">await</span> <span style="color: rgba(0, 0, 255, 1)">using</span> <span style="color: rgba(0, 0, 255, 1)">var</span> scope =<span style="color: rgba(0, 0, 0, 1)"> _serviceProvider.CreateAsyncScope();
</span><span style="color: rgba(0, 128, 128, 1)">24</span>         <span style="color: rgba(0, 0, 255, 1)">foreach</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> server <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> Servers)
</span><span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 0, 0, 1)">      {
</span><span style="color: rgba(0, 128, 128, 1)">26</span>             <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 根据服务名称获取服务</span>
<span style="color: rgba(0, 128, 128, 1)">27</span>             <span style="color: rgba(0, 0, 255, 1)">var</span> testServices = scope.ServiceProvider.GetKeyedServices&lt;ITestService&gt;<span style="color: rgba(0, 0, 0, 1)">(server.Key);
</span><span style="color: rgba(0, 128, 128, 1)">28</span>             <span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (testServices.Any())
</span><span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 0, 0, 1)">            {
</span><span style="color: rgba(0, 128, 128, 1)">30</span>               <span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)">正常来说一个任务对应一个服务,这里只取第一个</span>
<span style="color: rgba(0, 128, 128, 1)">31</span>               <span style="color: rgba(0, 0, 255, 1)">var</span> testService =<span style="color: rgba(0, 0, 0, 1)"> testServices.First();
</span><span style="color: rgba(0, 128, 128, 1)">32</span>               <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 添加定时任务</span>
<span style="color: rgba(0, 128, 128, 1)">33</span>               TaskServicesManager.GetOrAdd(server.Key, <span style="color: rgba(0, 0, 255, 1)">async</span> (serviceProvider, token) =&gt;
<span style="color: rgba(0, 128, 128, 1)">34</span> <span style="color: rgba(0, 0, 0, 1)">                {
</span><span style="color: rgba(0, 128, 128, 1)">35</span>                     <span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> testService.Run(serviceProvider);
</span><span style="color: rgba(0, 128, 128, 1)">36</span> <span style="color: rgba(0, 0, 0, 1)">                }, TriggerBuilder.Build(server.Value));
</span><span style="color: rgba(0, 128, 128, 1)">37</span> <span style="color: rgba(0, 0, 0, 1)">            }
</span><span style="color: rgba(0, 128, 128, 1)">38</span> <span style="color: rgba(0, 0, 0, 1)">      }
</span><span style="color: rgba(0, 128, 128, 1)">39</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">40</span>
<span style="color: rgba(0, 128, 128, 1)">41</span>   <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Task StopAsync(CancellationToken cancellationToken)
</span><span style="color: rgba(0, 128, 128, 1)">42</span> <span style="color: rgba(0, 0, 0, 1)">    {
</span><span style="color: rgba(0, 128, 128, 1)">43</span>         Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">StopAsync</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">44</span>
<span style="color: rgba(0, 128, 128, 1)">45</span>         <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> Task.CompletedTask;
</span><span style="color: rgba(0, 128, 128, 1)">46</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">47</span> }</pre>
</div>
<p>  代码就这么多,感谢各位大佬的观看!</p>

</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:一事冇诚,转载请注明原文链接:https://www.cnblogs.com/ysmc/p/18795934</p><br><br>
来源:https://www.cnblogs.com/ysmc/p/18795934
頁: [1]
查看完整版本: Longbow.Tasks 实战—任务持久化