83 lines
2.6 KiB
Go
83 lines
2.6 KiB
Go
// Filename: internal/scheduler/scheduler.go
|
||
package scheduler
|
||
|
||
import (
|
||
"context"
|
||
"gemini-balancer/internal/repository"
|
||
"gemini-balancer/internal/service"
|
||
"time"
|
||
|
||
"github.com/go-co-op/gocron"
|
||
"github.com/sirupsen/logrus"
|
||
)
|
||
|
||
type Scheduler struct {
|
||
gocronScheduler *gocron.Scheduler
|
||
logger *logrus.Entry
|
||
statsService *service.StatsService
|
||
keyRepo repository.KeyRepository
|
||
}
|
||
|
||
func NewScheduler(statsSvc *service.StatsService, keyRepo repository.KeyRepository, logger *logrus.Logger) *Scheduler {
|
||
s := gocron.NewScheduler(time.UTC)
|
||
s.TagsUnique()
|
||
return &Scheduler{
|
||
gocronScheduler: s,
|
||
logger: logger.WithField("component", "Scheduler📆"),
|
||
statsService: statsSvc,
|
||
keyRepo: keyRepo,
|
||
}
|
||
}
|
||
|
||
func (s *Scheduler) Start() {
|
||
s.logger.Info("Starting scheduler and registering jobs...")
|
||
|
||
// 任务一:每小时执行一次的统计聚合
|
||
// 使用CRON表达式,精确定义“每小时的第5分钟”执行
|
||
_, err := s.gocronScheduler.Cron("5 * * * *").Tag("stats-aggregation").Do(func() {
|
||
s.logger.Info("Executing hourly request stats aggregation...")
|
||
// 为后台定时任务创建一个新的、空的 context
|
||
ctx := context.Background()
|
||
if err := s.statsService.AggregateHourlyStats(ctx); err != nil {
|
||
s.logger.WithError(err).Error("Hourly stats aggregation failed.")
|
||
} else {
|
||
s.logger.Info("Hourly stats aggregation completed successfully.")
|
||
}
|
||
})
|
||
if err != nil {
|
||
s.logger.Errorf("Failed to schedule [stats-aggregation]: %v", err)
|
||
}
|
||
|
||
// 任务二:(预留) 自动健康检查
|
||
|
||
// 任务三:每日执行一次的软删除Key清理
|
||
// Executes once daily at 3:15 AM UTC.
|
||
_, err = s.gocronScheduler.Cron("15 3 * * *").Tag("cleanup-soft-deleted-keys").Do(func() {
|
||
s.logger.Info("Executing daily cleanup of soft-deleted API keys...")
|
||
|
||
// [假设保留7天,实际应来自配置
|
||
const retentionDays = 7
|
||
|
||
count, err := s.keyRepo.HardDeleteSoftDeletedBefore(time.Now().AddDate(0, 0, -retentionDays))
|
||
if err != nil {
|
||
s.logger.WithError(err).Error("Daily cleanup of soft-deleted keys failed.")
|
||
} else if count > 0 {
|
||
s.logger.Infof("Daily cleanup completed: Permanently deleted %d expired soft-deleted keys.", count)
|
||
} else {
|
||
s.logger.Info("Daily cleanup completed: No expired soft-deleted keys found to delete.")
|
||
}
|
||
})
|
||
if err != nil {
|
||
s.logger.Errorf("Failed to schedule [cleanup-soft-deleted-keys]: %v", err)
|
||
}
|
||
|
||
s.gocronScheduler.StartAsync()
|
||
s.logger.Info("Scheduler started.")
|
||
}
|
||
|
||
func (s *Scheduler) Stop() {
|
||
s.logger.Info("Stopping scheduler...")
|
||
s.gocronScheduler.Stop()
|
||
s.logger.Info("Scheduler stopped.")
|
||
}
|