gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/sync/cron.go (about) 1 package sync 2 3 import ( 4 "fmt" 5 "math" 6 "time" 7 8 "gitee.com/liuxuezhan/go-micro-v1.18.0/sync/leader/etcd" 9 "gitee.com/liuxuezhan/go-micro-v1.18.0/sync/task" 10 "gitee.com/liuxuezhan/go-micro-v1.18.0/sync/task/local" 11 "gitee.com/liuxuezhan/go-micro-v1.18.0/util/log" 12 ) 13 14 type syncCron struct { 15 opts Options 16 } 17 18 func backoff(attempts int) time.Duration { 19 if attempts == 0 { 20 return time.Duration(0) 21 } 22 return time.Duration(math.Pow(10, float64(attempts))) * time.Millisecond 23 } 24 25 func (c *syncCron) Schedule(s task.Schedule, t task.Command) error { 26 id := fmt.Sprintf("%s-%s", s.String(), t.String()) 27 28 go func() { 29 // run the scheduler 30 tc := s.Run() 31 32 var i int 33 34 for { 35 // leader election 36 e, err := c.opts.Leader.Elect(id) 37 if err != nil { 38 log.Logf("[cron] leader election error: %v", err) 39 time.Sleep(backoff(i)) 40 i++ 41 continue 42 } 43 44 i = 0 45 r := e.Revoked() 46 47 // execute the task 48 Tick: 49 for { 50 select { 51 // schedule tick 52 case _, ok := <-tc: 53 // ticked once 54 if !ok { 55 break Tick 56 } 57 58 log.Logf("[cron] executing command %s", t.Name) 59 if err := c.opts.Task.Run(t); err != nil { 60 log.Logf("[cron] error executing command %s: %v", t.Name, err) 61 } 62 // leader revoked 63 case <-r: 64 break Tick 65 } 66 } 67 68 // resign 69 e.Resign() 70 } 71 }() 72 73 return nil 74 } 75 76 func NewCron(opts ...Option) Cron { 77 var options Options 78 for _, o := range opts { 79 o(&options) 80 } 81 82 if options.Leader == nil { 83 options.Leader = etcd.NewLeader() 84 } 85 86 if options.Task == nil { 87 options.Task = local.NewTask() 88 } 89 90 return &syncCron{ 91 opts: options, 92 } 93 }