gitee.com/quant1x/gox@v1.21.2/coroutine/periodic_once.go (about)

     1  package coroutine
     2  
     3  import (
     4  	"gitee.com/quant1x/gox/cron"
     5  	"gitee.com/quant1x/gox/logger"
     6  	"gitee.com/quant1x/gox/runtime"
     7  	"sync"
     8  	"sync/atomic"
     9  	"time"
    10  )
    11  
    12  const (
    13  	cronPreMinute       = "*/1 * * * *"
    14  	cronPreSecond       = "*/1 * * * * ?"
    15  	cronDefaultInterval = "@every 1s"
    16  	periodicInitTime    = "09:00:00"
    17  )
    18  
    19  // PeriodicOnce 周期性懒加载机制
    20  //
    21  // Deprecated: 推荐 RollingOnce [wangfeng on 2024/1/22 10:33]
    22  type PeriodicOnce struct {
    23  	done     uint32
    24  	m        sync.Mutex
    25  	once     sync.Once
    26  	timer    *cron.Cron
    27  	date     string
    28  	lazyFunc func()
    29  }
    30  
    31  func (o *PeriodicOnce) Do(f func()) {
    32  	if o.lazyFunc == nil {
    33  		o.lazyFunc = f
    34  	}
    35  	o.once.Do(o.initTimer)
    36  	if atomic.LoadUint32(&o.done) == 0 {
    37  		o.doSlow(f)
    38  	}
    39  }
    40  
    41  func (o *PeriodicOnce) doSlow(f func()) {
    42  	o.m.Lock()
    43  	defer o.m.Unlock()
    44  	if o.done == 0 {
    45  		defer atomic.StoreUint32(&o.done, 1)
    46  		f()
    47  	}
    48  }
    49  
    50  func (o *PeriodicOnce) isExpired() bool {
    51  	currentDate := o.date
    52  	if currentDate < onceDefaultDate {
    53  		currentDate = onceDefaultDate
    54  	}
    55  	now := time.Now()
    56  	timestamp := now.Format(time.TimeOnly)
    57  	if timestamp >= periodicInitTime {
    58  		currentDate = now.Format(time.DateOnly)
    59  	}
    60  	if currentDate > o.date {
    61  		return true
    62  	}
    63  	return false
    64  }
    65  
    66  func (o *PeriodicOnce) initTimer() {
    67  	if o.timer == nil {
    68  		funcName := runtime.FuncName(o.lazyFunc)
    69  		o.timer = cron.New(cron.WithSeconds())
    70  		_, err := o.timer.AddFuncWithSkipIfStillRunning(cronDefaultInterval, func() {
    71  			if o.isExpired() {
    72  				if runtime.Debug() {
    73  					logger.Infof("PeriodicOnce[%s]: reset begin", funcName)
    74  				}
    75  				o.Reset()
    76  				if runtime.Debug() {
    77  					logger.Infof("PeriodicOnce[%s]: reset end", funcName)
    78  				}
    79  			}
    80  		})
    81  		if err == nil {
    82  			o.timer.Start()
    83  		}
    84  	}
    85  }
    86  
    87  // Reset 被动的方式重置初始化done标志
    88  func (o *PeriodicOnce) Reset() {
    89  	if atomic.LoadUint32(&o.done) == 1 {
    90  		o.resetSlow()
    91  	}
    92  }
    93  
    94  func (o *PeriodicOnce) resetSlow() {
    95  	o.m.Lock()
    96  	defer o.m.Unlock()
    97  	if o.done == 1 {
    98  		atomic.StoreUint32(&o.done, 0)
    99  		// 重置日期
   100  		now := time.Now()
   101  		o.date = now.Format(time.DateOnly)
   102  	}
   103  }