golang achieve regular tasks

In the actual development process, we sometimes need to write some regular tasks. Of course, we can use the crontabcommand to achieve our needs. However, this method does not meet some of the customization scene, and it will depend on the specific operating system environment.

Regular tasks

In golangwe can use cron to achieve our demands regular tasks. His use is very simple, specific code as follows:

package main
import(
  "fmt"
  
    cron "github.com/robfig/cron/v3"
)

func main() {
    crontab := cron.New()
    task := func() {
        fmt.Println("hello world")
    }
  // 添加定时任务, * * * * * 是 crontab,表示每分钟执行一次
    crontab.AddFunc("* * * * *", task)
  // 启动定时器
    crontab.Start()
  // 定时任务是另起协程执行的,这里使用 select 简答阻塞.实际开发中需要
  // 根据实际情况进行控制
    select {}
}

Note:

  • New () function supports multiple initialization options, such ascron.WithPanicLogger
  • Timing task from another coroutine execution

Above is the easiest to use cron example, if you need more detailed understanding of usage, you can refer to the official documentation and examples.

Custom Packaging

In using the method on the basis of the above, based on my actual demand, I cronlibraries were simple packaging, primarily for the realization of the following a few requirements:

  • Manages all timed tasks, need to record the number of regular tasks and related information
  • Stop a scheduled task
  • Support add the function type and interface type tasks

Man of few words said, directly attached to the code:

package main

import (
    "fmt"
    "sync"

    "github.com/pkg/errors"
    cron "github.com/robfig/cron/v3"
)

// Crontab crontab manager
type Crontab struct {
    inner *cron.Cron
    ids   map[string]cron.EntryID
    mutex sync.Mutex
}

// NewCrontab new crontab
func NewCrontab() *Crontab {
    return &Crontab{
        inner: cron.New(),
        ids:   make(map[string]cron.EntryID),
    }
}

// IDs ...
func (c *Crontab) IDs() []string {
    c.mutex.Lock()
    defer c.mutex.Unlock()
    validIDs := make([]string, 0, len(c.ids))
    invalidIDs := make([]string, 0)
    for sid, eid := range c.ids {
        if e := c.inner.Entry(eid); e.ID != eid {
            invalidIDs = append(invalidIDs, sid)
            continue
        }
        validIDs = append(validIDs, sid)
    }
    for _, id := range invalidIDs {
        delete(c.ids, id)
    }
    return validIDs
}

// Start start the crontab engine
func (c *Crontab) Start() {
    c.inner.Start()
}

// Stop stop the crontab engine
func (c *Crontab) Stop() {
    c.inner.Stop()
}

// DelByID remove one crontab task
func (c *Crontab) DelByID(id string) {
    c.mutex.Lock()
    defer c.mutex.Unlock()

    eid, ok := c.ids[id]
    if !ok {
        return
    }
    c.inner.Remove(eid)
    delete(c.ids, id)
}

// AddByID add one crontab task
// id is unique
// spec is the crontab expression
func (c *Crontab) AddByID(id string, spec string, cmd cron.Job) error {
    c.mutex.Lock()
    defer c.mutex.Unlock()

    if _, ok := c.ids[id]; ok {
        return errors.Errorf("crontab id exists")
    }
    eid, err := c.inner.AddJob(spec, cmd)
    if err != nil {
        return err
    }
    c.ids[id] = eid
    return nil
}

// AddByFunc add function as crontab task
func (c *Crontab) AddByFunc(id string, spec string, f func()) error {
    c.mutex.Lock()
    defer c.mutex.Unlock()

    if _, ok := c.ids[id]; ok {
        return errors.Errorf("crontab id exists")
    }
    eid, err := c.inner.AddFunc(spec, f)
    if err != nil {
        return err
    }
    c.ids[id] = eid
    return nil
}

// IsExists check the crontab task whether existed with job id
func (c *Crontab) IsExists(jid string) bool {
    _, exist := c.ids[jid]
    return exist
}

Code is very simple to achieve, the role of each function can refer to the following comments simple and practical at the above package:

type testTask struct {
}

func (t *testTask) Run() {
    fmt.Println("hello world")
}

func main() {
    crontab := NewCrontab()
    // 实现接口的方式添加定时任务
    task := &testTask{}
    if err := crontab.AddByID("1", "* * * * *", task); err != nil {
        fmt.Printf("error to add crontab task:%s", err)
        os.Exit(-1)
    }

    // 添加函数作为定时任务
    taskFunc := func() {
        fmt.Println("hello world")
    }
    if err := crontab.AddByFunc("2", "* * * * *", taskFunc); err != nil {
        fmt.Printf("error to add crontab task:%s", err)
        os.Exit(-1)
    }
    crontab.Start()
    select {}

}

Note:

  • task id is unique, the actual development can use uuid
  • This package is complicated by security

insufficient:

  • Not support initialization parameters
  • Timing errors collection task, if a cron job error, the error should be able to obtain information (in this case is wrong not panic)
  • panic recovery operation can refer withChain, andcron.Recover

postscript

Next parsing the detailed implementation of the principle of cron and more complex usage

Guess you like

Origin www.cnblogs.com/jssyjam/p/11910851.html