github.com/wfusion/gofusion@v1.1.14/common/infra/asynq/syncer.go (about) 1 // Copyright 2020 Kentaro Hibino. All rights reserved. 2 // Use of this source code is governed by a MIT license 3 // that can be found in the LICENSE file. 4 5 package asynq 6 7 import ( 8 "sync" 9 "time" 10 11 "github.com/wfusion/gofusion/common/infra/asynq/pkg/log" 12 ) 13 14 // syncer is responsible for queuing up failed requests to redis and retry 15 // those requests to sync state between the background process and redis. 16 type syncer struct { 17 logger *log.Logger 18 19 requestsCh <-chan *syncRequest 20 21 // channel to communicate back to the long running "syncer" goroutine. 22 done chan struct{} 23 24 // interval between sync operations. 25 interval time.Duration 26 } 27 28 type syncRequest struct { 29 fn func() error // sync operation 30 errMsg string // error message 31 deadline time.Time // request should be dropped if deadline has been exceeded 32 } 33 34 type syncerParams struct { 35 logger *log.Logger 36 requestsCh <-chan *syncRequest 37 interval time.Duration 38 } 39 40 func newSyncer(params syncerParams) *syncer { 41 return &syncer{ 42 logger: params.logger, 43 requestsCh: params.requestsCh, 44 done: make(chan struct{}), 45 interval: params.interval, 46 } 47 } 48 49 func (s *syncer) shutdown() { 50 s.logger.Debug("Syncer shutting down...") 51 // Signal the syncer goroutine to stop. 52 s.done <- struct{}{} 53 } 54 55 func (s *syncer) start(wg *sync.WaitGroup) { 56 wg.Add(1) 57 go func() { 58 defer wg.Done() 59 var requests []*syncRequest 60 for { 61 select { 62 case <-s.done: 63 // Try sync one last time before shutting down. 64 for _, req := range requests { 65 if err := req.fn(); err != nil { 66 s.logger.Error(req.errMsg) 67 } 68 } 69 s.logger.Debug("Syncer done") 70 return 71 case req := <-s.requestsCh: 72 requests = append(requests, req) 73 case <-time.After(s.interval): 74 var temp []*syncRequest 75 for _, req := range requests { 76 if req.deadline.Before(time.Now()) { 77 continue // drop stale request 78 } 79 if err := req.fn(); err != nil { 80 temp = append(temp, req) 81 } 82 } 83 requests = temp 84 } 85 } 86 }() 87 }