linux自带的crontab默认情况下只能精确到分钟,没法执行秒级任务。当然,也不是不行,比如:
* * * * * for i in $(seq 1 11);do echo hello >> /home/heruos/tmp.txt;sleep 5;done
看起来low了点,但也不是不能用。本文推荐go的一个第三方模块——gocron,配置定时任务也相当简单。
安装
go get -u github.com/go-co-op/gocron
基础使用示例
package main
import (
"fmt"
"time"
"github.com/go-co-op/gocron"
)
func cron1() {
fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
}
func main() {
timezone,_ := time.LoadLocation("Asia/Shanghai")
s := gocron.NewScheduler(timezone)
// 每3秒执行一次
s.Every(3).Seconds().Do(cron1)
s.StartBlocking()
}
定时示例
// 每5秒执行一次
s.Every(5).Seconds().Do(func(){ ... })
// 每5天执行
s.Every(5).Days().Do(func(){ ... })
// 解析字符串。每5秒执行
s.Every("5s").Do(cron2)
// 每月1号、2号和3号的10:00执行一次
s.Every(1).Month(1,2,3).At("10:00").Do(func(){ ... })
// 每天10:30执行一次
s.Every(1).Day().At("10:30").Do(func(){ ... })
// 每天10:30和08:00执行一次
s.Every(1).Day().At("10:30;08:00").Do(func(){ ... })
// 解析crontab表达式,每分钟执行一次
s.Cron("* * * * *").Do(func(){ ... })
启动方式
启动scheduler有两种方式:
- s.StartAsync():启动所有任务,非阻塞当前goroutine
- s.StartBlocking():启动所有任务,并阻塞当前goroutine
示例: 解析文件并配置定时任务
功能描述:读取配置文件,根据配置文件设置定时任务。配置文件第一列为任务执行间隔时间,第二列为可执行文件路径。用逗号隔开。
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
"strconv"
"strings"
"time"
"github.com/go-co-op/gocron"
)
func cmdOnly(cmd string) {
// 只运行命令
cmdTmp := exec.Command("bash", "-c", cmd)
if err := cmdTmp.Run(); err != nil {
panic(err)
}
}
func ParseCmds(cmdconf string) (int, string) {
/*
分割配置文件中每行字符串,
第一列为任务执行间隔时间秒数,
第二列为具体任务的命令或可执行脚本位置
*/
rst := strings.Split(cmdconf, ",")
cronTime, err := strconv.Atoi(rst[0])
if err != nil {
log.Fatal(err)
}
cmd := rst[1]
fmt.Printf("定时任务: %s, 任务执行间隔时间: %d秒\n",cmd,cronTime)
return cronTime, cmd
}
func ReadConf(filepath string) []string {
// 读取cron任务文件,并返回一个包含所有任务的切片
file, err := os.Open(filepath)
if err != nil {
strTmp := fmt.Sprintf("打开 %s 文件失败\n",filepath)
panic(strTmp)
}
defer func() {
if err = file.Close(); err != nil {
fmt.Println("文件关闭失败,", err)
}
}()
sc := bufio.NewScanner(file)
// 不保存到切片中,直接解析每行字符串然后配置成定时任务应该也行
// 这里主要是要分开各个函数的功能
cmds := make([]string, 0)
for sc.Scan() {
// 将每行内容追加到切片中
cmds = append(cmds, sc.Text())
}
if err = sc.Err(); err != nil {
fmt.Println("文件操作失败,", err)
}
return cmds
}
func main() {
timezone, _ := time.LoadLocation("Asia/Shanghai")
scheduler := gocron.NewScheduler(timezone)
var cronfile string = "./second_works.txt"
cmds := ReadConf(cronfile)
for _, v := range cmds {
// fmt.Println(v)
cronTime, cmd := ParseCmds(v)
_,_ = scheduler.Every(cronTime).Seconds().Do(cmdOnly,cmd)
}
fmt.Println("mycron启动, version: 1.0.0, 任务清单文件为: ./second_works.txt")
scheduler.StartBlocking()
}
网友评论