mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-02 14:56:38 +08:00
98 lines
2.2 KiB
Go
98 lines
2.2 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package tasks
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
|
|
"github.com/Rain-kl/Wavelet/pkg/logger"
|
|
"github.com/robfig/cron/v3"
|
|
)
|
|
|
|
type cronJob struct {
|
|
name string
|
|
spec string
|
|
run func(context.Context)
|
|
}
|
|
|
|
var (
|
|
registryMu sync.Mutex
|
|
started bool
|
|
cronJobs []cronJob
|
|
cronRunner *cron.Cron
|
|
jobCtx context.Context
|
|
jobCancel context.CancelFunc
|
|
)
|
|
|
|
func registerJob(name, cronSpec string, fn func(context.Context)) {
|
|
registryMu.Lock()
|
|
defer registryMu.Unlock()
|
|
cronJobs = append(cronJobs, cronJob{name: name, spec: cronSpec, run: fn})
|
|
}
|
|
|
|
// RegisterCronJob registers a cron job from another OpenFlare package (for example waf).
|
|
// Prefer registerJob from init() inside this package when possible.
|
|
func RegisterCronJob(name, cronSpec string, fn func(context.Context)) {
|
|
registerJob(name, cronSpec, fn)
|
|
}
|
|
|
|
// LogJobError records a failed OpenFlare cron job run.
|
|
func LogJobError(ctx context.Context, name string, err error) {
|
|
logger.ErrorF(ctx, "[OpenFlareTasks] %s failed: %v", name, err)
|
|
}
|
|
|
|
// Start launches the cron scheduler in a background goroutine. Safe to call multiple times.
|
|
func Start(ctx context.Context) {
|
|
registryMu.Lock()
|
|
defer registryMu.Unlock()
|
|
if started {
|
|
return
|
|
}
|
|
|
|
jobCtx, jobCancel = context.WithCancel(context.Background())
|
|
runner := cron.New()
|
|
for _, job := range cronJobs {
|
|
current := job
|
|
if _, err := runner.AddFunc(current.spec, func() {
|
|
current.run(jobCtx)
|
|
}); err != nil {
|
|
logger.ErrorF(ctx, "[OpenFlareTasks] register cron job %q failed: %v", current.name, err)
|
|
continue
|
|
}
|
|
logger.InfoF(ctx, "[OpenFlareTasks] registered cron job %q (%s)", current.name, current.spec)
|
|
}
|
|
runner.Start()
|
|
cronRunner = runner
|
|
started = true
|
|
}
|
|
|
|
// Stop shuts down the cron scheduler gracefully and cancels job contexts.
|
|
func Stop() {
|
|
registryMu.Lock()
|
|
defer registryMu.Unlock()
|
|
if !started || cronRunner == nil {
|
|
return
|
|
}
|
|
|
|
stopCtx := cronRunner.Stop()
|
|
<-stopCtx.Done()
|
|
if jobCancel != nil {
|
|
jobCancel()
|
|
}
|
|
|
|
cronRunner = nil
|
|
started = false
|
|
jobCtx = nil
|
|
jobCancel = nil
|
|
}
|
|
|
|
// ResetRegistryForTest clears scheduler state so unit tests can call Start again.
|
|
func ResetRegistryForTest() {
|
|
Stop()
|
|
registryMu.Lock()
|
|
defer registryMu.Unlock()
|
|
cronJobs = nil
|
|
}
|