go 定时任务库 cron
<h1 id="简介">简介</h1><p>在Linux中,<code>Cron</code>是计划任务管理系统,通过<code>crontab</code>命令使任务在约定的时间执行已经计划好的工作,例如定时备份系统数据、周期性清理缓存、定时重启服务等。</p>
<p>本文介绍的<code>cron</code>库是一个用于管理定时任务的库,就是用Go实现Linux中<code>crontab</code>命令的相似效果。</p>
<h1 id="快速使用">快速使用</h1>
<p>文本代码使用 <code>Go Modules</code>。</p>
<p>创建目录并初始化:</p>
<pre><code>$ mkdir cron && cd cron
$ go mod init cron
</code></pre>
<p>安装<code>cron</code>,目前最新稳定版本为 v3:</p>
<pre><code>$ go get -u github.com/robfig/cron/v3
</code></pre>
<p>在项目中导入包使用:</p>
<pre><code>package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New()
c.AddFunc("@every 1s", func() {
fmt.Println("tick every 1 second")
})
c.Start()
// 阻塞,或者使用其他延迟时间函数、
select{}
}
</code></pre>
<p>使用非常简单,创建<code>cron</code>对象,这个对象用于管理定时任务。</p>
<p>调用<code>cron</code>对象的<code>AddFunc()</code>方法向管理器中添加定时任务。<code>AddFunc()</code>接受两个参数,参数 1 以字符串形式指定触发时间规则,参数 2 是一个无参的函数,每次触发时调用。<code>@every 1s</code>表示每秒触发一次,<code>@every</code>后加一个时间间隔,表示每隔多长时间触发一次。例如<code>@every 1h</code>表示每小时触发一次,<code>@every 1m2s</code>表示每隔 1 分 2 秒触发一次。<code>time.ParseDuration()</code>支持的格式都可以用在这里。</p>
<p>调用<code>c.Start()</code>启动定时循环。</p>
<p>注意一点,因为<code>c.Start()</code>启动一个新的 <code>goroutine</code> 做循环检测,我们在代码最后加了一行<code>time.Sleep(time.Second * 5)</code>防止主 <code>goroutine</code> 退出。</p>
<p>运行效果,每隔 1s 输出一行字符串:</p>
<pre><code>$ go run main.go
tick every 1 second
tick every 1 second
tick every 1 second
tick every 1 second
tick every 1 second
</code></pre>
<h1 id="时间格式">时间格式</h1>
<p>与Linux 中crontab命令相似,cron库支持用 5 个空格分隔的域来表示时间。</p>
<table>
<thead>
<tr>
<th>字段名</th>
<th>是否必须</th>
<th>允许的值</th>
<th>允许的特定字符</th>
</tr>
</thead>
<tbody>
<tr>
<td>秒(Seconds)</td>
<td>是</td>
<td>0-59</td>
<td>* / , -</td>
</tr>
<tr>
<td>分(Minute)</td>
<td>是</td>
<td>0-59</td>
<td>* / , -</td>
</tr>
<tr>
<td>时(Hours)</td>
<td>是</td>
<td>0-23</td>
<td>* / , -</td>
</tr>
<tr>
<td>日(Day of month)</td>
<td>是</td>
<td>1-31</td>
<td>* / , - ?</td>
</tr>
<tr>
<td>月(Month)</td>
<td>是</td>
<td>1-12 或 JAN-DEC</td>
<td>* / , -</td>
</tr>
<tr>
<td>星期(Day of week)</td>
<td>否</td>
<td>0-6 或 SUM-SAT</td>
<td>* / , - ?</td>
</tr>
</tbody>
</table>
<p>注意,月份和周历名称都是不区分大小写的,也就是说SUN/Sun/sun表示同样的含义(都是周日)。</p>
<p>特殊字符含义如下:</p>
<ul>
<li>星号(<em>):使用</em>的域可以匹配任何值,例如将月份域(第 5 个)设置为*,表示每个月;</li>
<li>斜线(/):用来指定范围的步长,例如如第1个字段(minutes) 值是 3-59/15,表示每小时的第3分钟开始执行一次,之后每隔 15 分钟执行一次(即 3、18、33、48 这些时间点执行),这里也可以表示为:3/15;</li>
<li>逗号(,):用来列举一些离散的值和多个范围,例如将周历的域(第 6 个)设置为MON,WED,FRI表示周一、三和五;</li>
<li>连字号(-):用来表示范围,例如将小时的域(第 3 个)设置为9-17表示上午 9 点到下午 17 点(包括 9 和 17);</li>
<li>问号(?):只能用在月历和周历的域中,用来代替*,表示每月/周的任意一天。</li>
<li>(L,W,#): Go中没有L,W,#的用法</li>
</ul>
<p>了解规则之后,我们可以定义任意时间:</p>
<pre><code>每隔5秒执行一次:*/5 * * * * ?
每隔1分钟执行一次:0 */1 * * * ?
每天23点执行一次:0 0 23 * * ?
每天凌晨1点执行一次:0 0 1 * * ?
每月1号凌晨1点执行一次:0 0 1 1 * ?
在26分、29分、33分执行一次:0 26,29,33 * * * ?
每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?
</code></pre>
<p>记熟了这几个域的顺序,再多练习几次很容易就能掌握格式。熟悉规则了之后,就能熟练使用<code>crontab</code>命令了。</p>
<pre><code>func main() {
c := cron.New()
c.AddFunc("30 * * * *", func() {
fmt.Println("Every hour on the half hour")
})
c.AddFunc("30 3-6,20-23 * * *", func() {
fmt.Println("On the half hour of 3-6am, 8-11pm")
})
c.AddFunc("0 0 1 1 *", func() {
fmt.Println("Jun 1 every year")
})
c.Start()
for {
time.Sleep(time.Second)
}
}
</code></pre>
<h2 id="预定义时间规则">预定义时间规则</h2>
<p>为了方便使用,cron预定义了一些时间规则:</p>
<ul>
<li>@yearly:也可以写作@annually,表示每年第一天的 0 点。等价于0 0 1 1 *;</li>
<li>@monthly:表示每月第一天的 0 点。等价于0 0 1 * *;</li>
<li>@weekly:表示每周第一天的 0 点,注意第一天为周日,即周六结束,周日开始的那个 0 点。等价于0 0 * * 0;</li>
<li>@daily:也可以写作@midnight,表示每天 0 点。等价于0 0 * * *;</li>
<li>@hourly:表示每小时的开始。等价于0 * * * *。</li>
</ul>
<p>例如:</p>
<pre><code>func main() {
c := cron.New()
c.AddFunc("@hourly", func() {
fmt.Println("Every hour")
})
c.AddFunc("@daily", func() {
fmt.Println("Every day on midnight")
})
c.AddFunc("@weekly", func() {
fmt.Println("Every week")
})
c.Start()
for {
time.Sleep(time.Second)
}
}
</code></pre>
<p>上面代码只是演示用法,实际运行可能要等待非常长的时间才能有输出。</p>
<blockquote>
<p>注意:这样使用一个 <code>cron.New()</code> 的定时任务,执行的每个方法是顺序执行的,也就是说并不是同一时刻开始执行</p>
</blockquote>
<h2 id="固定时间间隔">固定时间间隔</h2>
<p><code>cron</code>支持固定时间间隔,格式为:</p>
<pre><code>@every <duration>
</code></pre>
<p>含义为每隔<code>duration</code>触发一次。<code><duration></code>会调用<code>time.ParseDuration()</code>函数解析,所以<code>ParseDuration</code>支持的格式都可以。例如<code>1h30m10s</code>。</p>
<h2 id="时区">时区</h2>
<p>默认情况下,所有时间都是基于当前时区的。当然我们也可以指定时区,有 2 两种方式:</p>
<ul>
<li>在时间字符串前面添加一个<code>CRON_TZ=</code> + 具体时区,具体时区的格式在之前carbon的文章中有详细介绍。东京时区为<code>Asia/Tokyo</code>,纽约时区为<code>America/New_York</code>;</li>
<li>创建<code>cron</code>对象时增加一个时区选项<code>cron.WithLocation(location)</code>,<code>location</code>为<code>time.LoadLocation(zone)</code>加载的时区对象,<code>zone</code>为具体的时区格式。或者调用已创建好的<code>cron</code>对象的<code>SetLocation()</code>方法设置时区。</li>
</ul>
<p>示例:</p>
<pre><code>func main() {
nyc, _ := time.LoadLocation("America/New_York")
c := cron.New(cron.WithLocation(nyc))
c.AddFunc("0 6 * * ?", func() {
fmt.Println("Every 6 o'clock at New York")
})
c.AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", func() {
fmt.Println("Every 6 o'clock at Tokyo")
})
c.Start()
for {
time.Sleep(time.Second)
}
}
</code></pre>
<h1 id="巨人的肩膀">巨人的肩膀</h1>
<p>Go 每日一库之 cron<br>
Go 每日一库之定时任务库:cron<br>
Go -- cron定时任务的用法</p><br><br>
来源:https://www.cnblogs.com/niuben/p/14615806.html
頁:
[1]