gitee.com/woood2/luca@v1.0.4/cmd/cron/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "gitee.com/woood2/luca/cmd/cron/internal/handler" 7 _ "gitee.com/woood2/luca/cmd/cron/internal/handler" 8 "gitee.com/woood2/luca/cmd/cron/internal/job" 9 lucaSDK "gitee.com/woood2/luca/cmd/micro/pkg" 10 "gitee.com/woood2/luca/internal/cache" 11 "gitee.com/woood2/luca/internal/conf" 12 "gitee.com/woood2/luca/internal/discovery" 13 myLog "gitee.com/woood2/luca/internal/log" 14 "gitee.com/woood2/luca/internal/status" 15 "gitee.com/woood2/luca/internal/trace" 16 consulsd "github.com/go-kit/kit/sd/consul" 17 "github.com/robfig/cron/v3" 18 "go.uber.org/zap" 19 "log" 20 "os" 21 "os/signal" 22 "runtime" 23 "syscall" 24 "time" 25 ) 26 27 const ( 28 entrance = "cron" 29 electionExpire = 30 * time.Second 30 campaignRetryFrequency = 5 * time.Second 31 renewFrequency = 20 * time.Second 32 ) 33 34 var electionKey string 35 36 func main() { 37 //load config 38 attr := conf.Load("application.yml", "configs/application.yml") 39 //consul 40 client, consulClient := discovery.Client(attr.Consul.Host, attr.Consul.Port) 41 conf.MergeConsul(attr, consulClient) 42 //election 43 electionKey = attr.Project + "-" + entrance + "-election" 44 //zap logger 45 logger := myLog.Build(attr.Env, attr.Project, entrance, attr.Host, attr.ConsoleLog) 46 defer logger.Sync() 47 //redis 48 redisCache := cache.NewRedis(attr.Redis) 49 cache.SetRedis(redisCache) 50 //zipkin 51 trace.Open(attr.Zipkin) 52 defer trace.Close() 53 //sdk 54 setupSDK(client, logger) 55 //Pprof 56 go status.Pprof(attr.Pprof, attr.Env, attr.Cron.PprofAddr) 57 //hystrix 58 go status.Hystrix(attr.Cron.HystrixPort) 59 //cron init 60 c := cron.New(cron.WithSeconds()) 61 handler.RegisterHandlers(attr.Project, entrance, logger) 62 jobs := job.List() 63 for _, job := range jobs { 64 c.AddJob(job.Spec, cron.NewChain(myRecover(logger)).Then(job)) 65 } 66 //campaign & start 67 go func() { 68 if err := campaign(); err != nil { 69 log.Panicf("campaigning err: %v\n", err) 70 } 71 log.Println("campaign success, cron start") 72 c.Start() 73 if err := renew(); err != nil { 74 log.Panicf("renewing err: %v\n", err) 75 } 76 }() 77 //graceful shutdown 78 quit := make(chan os.Signal) 79 signal.Notify(quit, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2) 80 <-quit 81 ctx := c.Stop() 82 t := time.NewTimer(5 * time.Second) 83 select { 84 case <-t.C: 85 log.Println("Shutting down server in 5 sec...") 86 case <-ctx.Done(): 87 log.Println("Shutting down server...") 88 } 89 } 90 91 //return if success 92 //keep retry if fail 93 func campaign() error { 94 rds := cache.Redis().Client 95 for { 96 resp := rds.SetNX(context.Background(), electionKey, 1, electionExpire) 97 succ, err := resp.Result() 98 if err != nil || !succ { 99 time.Sleep(campaignRetryFrequency) 100 continue 101 } 102 return nil 103 } 104 } 105 106 //keep delay expire 107 func renew() error { 108 rds := cache.Redis().Client 109 t := time.NewTicker(renewFrequency) 110 for { 111 <-t.C 112 resp := rds.Expire(context.Background(), electionKey, electionExpire) 113 succ, err := resp.Result() 114 if err != nil || !succ { 115 return err 116 } 117 } 118 } 119 120 func myRecover(logger *zap.Logger) cron.JobWrapper { 121 return func(j cron.Job) cron.Job { 122 return cron.FuncJob(func() { 123 defer func() { 124 if r := recover(); r != nil { 125 const size = 64 << 10 126 buf := make([]byte, size) 127 buf = buf[:runtime.Stack(buf, false)] 128 err, ok := r.(error) 129 if !ok { 130 err = fmt.Errorf("%v", r) 131 } 132 logger.Error("recover from panic", 133 zap.Any("err", err), 134 zap.String("stack", string(buf)), 135 ) 136 } 137 }() 138 j.Run() 139 }) 140 } 141 } 142 143 func setupSDK(client consulsd.Client, zapLogger *zap.Logger) { 144 lucaClient := lucaSDK.NewSD(client, "weibo2", "todo", zapLogger, trace.ClientTrace()) 145 lucaSDK.SetGlobal(lucaClient) 146 //More... 147 }