github.com/moqsien/xraycore@v1.8.5/common/task/periodic.go (about) 1 package task 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 // Periodic is a task that runs periodically. 9 type Periodic struct { 10 // Interval of the task being run 11 Interval time.Duration 12 // Execute is the task function 13 Execute func() error 14 15 access sync.Mutex 16 timer *time.Timer 17 running bool 18 } 19 20 func (t *Periodic) hasClosed() bool { 21 t.access.Lock() 22 defer t.access.Unlock() 23 24 return !t.running 25 } 26 27 func (t *Periodic) checkedExecute() error { 28 if t.hasClosed() { 29 return nil 30 } 31 32 if err := t.Execute(); err != nil { 33 t.access.Lock() 34 t.running = false 35 t.access.Unlock() 36 return err 37 } 38 39 t.access.Lock() 40 defer t.access.Unlock() 41 42 if !t.running { 43 return nil 44 } 45 46 t.timer = time.AfterFunc(t.Interval, func() { 47 t.checkedExecute() 48 }) 49 50 return nil 51 } 52 53 // Start implements common.Runnable. 54 func (t *Periodic) Start() error { 55 t.access.Lock() 56 if t.running { 57 t.access.Unlock() 58 return nil 59 } 60 t.running = true 61 t.access.Unlock() 62 63 if err := t.checkedExecute(); err != nil { 64 t.access.Lock() 65 t.running = false 66 t.access.Unlock() 67 return err 68 } 69 70 return nil 71 } 72 73 // Close implements common.Closable. 74 func (t *Periodic) Close() error { 75 t.access.Lock() 76 defer t.access.Unlock() 77 78 t.running = false 79 if t.timer != nil { 80 t.timer.Stop() 81 t.timer = nil 82 } 83 84 return nil 85 }