new-api/service/rebate_release_task.go
zizi b636142e27 fix: schedule affiliate rebate releases
Run an hourly rebate release task at startup so frozen affiliate rebates become transferable after expiry.
2026-05-20 15:56:46 +08:00

86 lines
1.5 KiB
Go

package service
import (
"log"
"sync"
"time"
)
var (
rebateReleaseOnce sync.Once
rebateReleaseStopMu sync.Mutex
rebateReleaseStopCh chan struct{}
rebateReleaseStopped bool
rebateReleaseRunMu sync.Mutex
rebateReleaseActive bool
)
func StartRebateReleaseTask() {
rebateReleaseOnce.Do(func() {
rebateReleaseStopMu.Lock()
defer rebateReleaseStopMu.Unlock()
rebateReleaseStopCh = make(chan struct{})
rebateReleaseStopped = false
go runRebateReleaseLoop(rebateReleaseStopCh)
})
}
func StopRebateReleaseTask() {
rebateReleaseStopMu.Lock()
defer rebateReleaseStopMu.Unlock()
if rebateReleaseStopCh != nil && !rebateReleaseStopped {
close(rebateReleaseStopCh)
rebateReleaseStopped = true
}
}
func RunRebateReleaseOnce() error {
if !markRebateReleaseRunning() {
return nil
}
defer unmarkRebateReleaseRunning()
return ReleaseExpiredRebates()
}
func runRebateReleaseLoop(stopCh <-chan struct{}) {
if err := RunRebateReleaseOnce(); err != nil {
log.Printf("rebate release: %v", err)
}
ticker := time.NewTicker(time.Hour)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if err := RunRebateReleaseOnce(); err != nil {
log.Printf("rebate release: %v", err)
}
case <-stopCh:
return
}
}
}
func markRebateReleaseRunning() bool {
rebateReleaseRunMu.Lock()
defer rebateReleaseRunMu.Unlock()
if rebateReleaseActive {
return false
}
rebateReleaseActive = true
return true
}
func unmarkRebateReleaseRunning() {
rebateReleaseRunMu.Lock()
defer rebateReleaseRunMu.Unlock()
rebateReleaseActive = false
}