mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-14 04:07:46 +00:00
131 lines
3.3 KiB
Go
131 lines
3.3 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// BackgroundTask provides a robust framework for running periodic background tasks
|
|
// with proper lifecycle management, graceful shutdown, and logging capabilities.
|
|
// It supports both internal and external WaitGroup coordination for complex cleanup scenarios.
|
|
type BackgroundTask struct {
|
|
stopChan chan struct{}
|
|
taskFunc func()
|
|
logger *Logger
|
|
externalWG *sync.WaitGroup
|
|
name string
|
|
internalWG sync.WaitGroup
|
|
interval time.Duration
|
|
stopOnce sync.Once
|
|
mu sync.Mutex
|
|
stopped bool
|
|
}
|
|
|
|
// NewBackgroundTask creates a new background task with the specified configuration.
|
|
// The task will execute taskFunc immediately when started, then at the specified interval.
|
|
// Parameters:
|
|
// - name: Human-readable name for the task (used in logging)
|
|
// - interval: How often to execute the task function
|
|
// - taskFunc: The function to execute periodically
|
|
// - logger: Logger for task events (can be nil)
|
|
// - wg: Optional external WaitGroup for coordinated shutdown
|
|
//
|
|
// Returns:
|
|
// - A configured BackgroundTask ready to be started
|
|
func NewBackgroundTask(name string, interval time.Duration, taskFunc func(), logger *Logger, wg ...*sync.WaitGroup) *BackgroundTask {
|
|
var externalWG *sync.WaitGroup
|
|
if len(wg) > 0 {
|
|
externalWG = wg[0]
|
|
}
|
|
return &BackgroundTask{
|
|
name: name,
|
|
interval: interval,
|
|
stopChan: make(chan struct{}),
|
|
taskFunc: taskFunc,
|
|
logger: logger,
|
|
externalWG: externalWG,
|
|
}
|
|
}
|
|
|
|
// Start begins executing the background task in a separate goroutine.
|
|
// The task function is executed immediately, then at the configured interval.
|
|
// The task runs immediately upon start and then at the specified interval.
|
|
func (bt *BackgroundTask) Start() {
|
|
bt.mu.Lock()
|
|
defer bt.mu.Unlock()
|
|
|
|
if bt.stopped {
|
|
if bt.logger != nil {
|
|
bt.logger.Infof("Attempted to start already stopped task: %s", bt.name)
|
|
}
|
|
return
|
|
}
|
|
|
|
bt.internalWG.Add(1)
|
|
if bt.externalWG != nil {
|
|
bt.externalWG.Add(1)
|
|
}
|
|
go bt.run()
|
|
}
|
|
|
|
// Stop gracefully shuts down the background task and waits for completion.
|
|
// It signals the task to stop and waits for the goroutine to finish.
|
|
// This method is safe to call multiple times.
|
|
func (bt *BackgroundTask) Stop() {
|
|
bt.stopOnce.Do(func() {
|
|
bt.mu.Lock()
|
|
bt.stopped = true
|
|
bt.mu.Unlock()
|
|
|
|
close(bt.stopChan)
|
|
bt.internalWG.Wait()
|
|
})
|
|
}
|
|
|
|
// run is the main loop for the background task.
|
|
// It executes the task function immediately, then periodically
|
|
// until the stop signal is received.
|
|
func (bt *BackgroundTask) run() {
|
|
defer func() {
|
|
bt.internalWG.Done()
|
|
if bt.externalWG != nil {
|
|
bt.externalWG.Done()
|
|
}
|
|
}()
|
|
ticker := time.NewTicker(bt.interval)
|
|
defer ticker.Stop()
|
|
|
|
if bt.logger != nil {
|
|
bt.logger.Info("Starting background task: %s", bt.name)
|
|
}
|
|
|
|
bt.taskFunc()
|
|
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
bt.taskFunc()
|
|
case <-bt.stopChan:
|
|
if bt.logger != nil {
|
|
bt.logger.Info("Stopping background task: %s", bt.name)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// autoCleanupRoutine is a legacy function for running periodic cleanup tasks.
|
|
// Deprecated: Use BackgroundTask instead for better lifecycle management and logging.
|
|
func autoCleanupRoutine(interval time.Duration, stop <-chan struct{}, cleanup func()) {
|
|
ticker := time.NewTicker(interval)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
cleanup()
|
|
case <-stop:
|
|
return
|
|
}
|
|
}
|
|
}
|