|
@@ -5,6 +5,7 @@ import (
|
|
"sync"
|
|
"sync"
|
|
"time"
|
|
"time"
|
|
|
|
|
|
|
|
+ "github.com/tal-tech/go-zero/core/lang"
|
|
"github.com/tal-tech/go-zero/core/proc"
|
|
"github.com/tal-tech/go-zero/core/proc"
|
|
"github.com/tal-tech/go-zero/core/syncx"
|
|
"github.com/tal-tech/go-zero/core/syncx"
|
|
"github.com/tal-tech/go-zero/core/threading"
|
|
"github.com/tal-tech/go-zero/core/threading"
|
|
@@ -32,19 +33,21 @@ type (
|
|
container TaskContainer
|
|
container TaskContainer
|
|
waitGroup sync.WaitGroup
|
|
waitGroup sync.WaitGroup
|
|
// avoid race condition on waitGroup when calling wg.Add/Done/Wait(...)
|
|
// avoid race condition on waitGroup when calling wg.Add/Done/Wait(...)
|
|
- wgBarrier syncx.Barrier
|
|
|
|
- guarded bool
|
|
|
|
- newTicker func(duration time.Duration) timex.Ticker
|
|
|
|
- lock sync.Mutex
|
|
|
|
|
|
+ wgBarrier syncx.Barrier
|
|
|
|
+ confirmChan chan lang.PlaceholderType
|
|
|
|
+ guarded bool
|
|
|
|
+ newTicker func(duration time.Duration) timex.Ticker
|
|
|
|
+ lock sync.Mutex
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
|
|
func NewPeriodicalExecutor(interval time.Duration, container TaskContainer) *PeriodicalExecutor {
|
|
func NewPeriodicalExecutor(interval time.Duration, container TaskContainer) *PeriodicalExecutor {
|
|
executor := &PeriodicalExecutor{
|
|
executor := &PeriodicalExecutor{
|
|
// buffer 1 to let the caller go quickly
|
|
// buffer 1 to let the caller go quickly
|
|
- commander: make(chan interface{}, 1),
|
|
|
|
- interval: interval,
|
|
|
|
- container: container,
|
|
|
|
|
|
+ commander: make(chan interface{}, 1),
|
|
|
|
+ interval: interval,
|
|
|
|
+ container: container,
|
|
|
|
+ confirmChan: make(chan lang.PlaceholderType),
|
|
newTicker: func(d time.Duration) timex.Ticker {
|
|
newTicker: func(d time.Duration) timex.Ticker {
|
|
return timex.NewTicker(interval)
|
|
return timex.NewTicker(interval)
|
|
},
|
|
},
|
|
@@ -59,10 +62,12 @@ func NewPeriodicalExecutor(interval time.Duration, container TaskContainer) *Per
|
|
func (pe *PeriodicalExecutor) Add(task interface{}) {
|
|
func (pe *PeriodicalExecutor) Add(task interface{}) {
|
|
if vals, ok := pe.addAndCheck(task); ok {
|
|
if vals, ok := pe.addAndCheck(task); ok {
|
|
pe.commander <- vals
|
|
pe.commander <- vals
|
|
|
|
+ <-pe.confirmChan
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func (pe *PeriodicalExecutor) Flush() bool {
|
|
func (pe *PeriodicalExecutor) Flush() bool {
|
|
|
|
+ pe.enterExecution()
|
|
return pe.executeTasks(func() interface{} {
|
|
return pe.executeTasks(func() interface{} {
|
|
pe.lock.Lock()
|
|
pe.lock.Lock()
|
|
defer pe.lock.Unlock()
|
|
defer pe.lock.Unlock()
|
|
@@ -114,6 +119,8 @@ func (pe *PeriodicalExecutor) backgroundFlush() {
|
|
select {
|
|
select {
|
|
case vals := <-pe.commander:
|
|
case vals := <-pe.commander:
|
|
commanded = true
|
|
commanded = true
|
|
|
|
+ pe.enterExecution()
|
|
|
|
+ pe.confirmChan <- lang.Placeholder
|
|
pe.executeTasks(vals)
|
|
pe.executeTasks(vals)
|
|
last = timex.Now()
|
|
last = timex.Now()
|
|
case <-ticker.Chan():
|
|
case <-ticker.Chan():
|
|
@@ -135,11 +142,18 @@ func (pe *PeriodicalExecutor) backgroundFlush() {
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
-func (pe *PeriodicalExecutor) executeTasks(tasks interface{}) bool {
|
|
|
|
|
|
+func (pe *PeriodicalExecutor) doneExecution() {
|
|
|
|
+ pe.waitGroup.Done()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (pe *PeriodicalExecutor) enterExecution() {
|
|
pe.wgBarrier.Guard(func() {
|
|
pe.wgBarrier.Guard(func() {
|
|
pe.waitGroup.Add(1)
|
|
pe.waitGroup.Add(1)
|
|
})
|
|
})
|
|
- defer pe.waitGroup.Done()
|
|
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (pe *PeriodicalExecutor) executeTasks(tasks interface{}) bool {
|
|
|
|
+ defer pe.doneExecution()
|
|
|
|
|
|
ok := pe.hasTasks(tasks)
|
|
ok := pe.hasTasks(tasks)
|
|
if ok {
|
|
if ok {
|