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  }