69 lines
1.9 KiB
Go

package storage
import (
"context"
"database/sql"
"log/slog"
"time"
)
func (r *MySQLRepository) StartGameReconciler(ctx context.Context, logger *slog.Logger) {
if !r.cfg.Game.Enabled || r.cfg.Game.Interval <= 0 {
return
}
run := func() {
since := currentStatDayStart(r.cfg.Dashboard.StatTimezones, r.cfg.Game.CurrentDayLag)
until := since.AddDate(0, 0, 1)
if err := r.RebuildGameMetricsRange(ctx, since, until); err != nil {
if r.metrics != nil {
r.metrics.RecordError(err)
}
logger.Error("dashboard game reconcile failed", "since", since, "until", until, "error", err)
return
}
logger.Info("dashboard game reconcile applied", "since", since, "until", until)
}
go func() {
run()
ticker := time.NewTicker(r.cfg.Game.Interval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
run()
}
}
}()
}
func (r *MySQLRepository) RebuildGameMetricsRange(ctx context.Context, start, end time.Time) error {
return r.WithDashboardLock(ctx, r.cfg.CDC.BackfillLockWait, func() error {
return r.WithTx(ctx, func(tx *sql.Tx) error {
for _, statTimezone := range r.cfg.Dashboard.StatTimezones {
location, err := time.LoadLocation(statTimezone)
if err != nil {
location = time.UTC
}
for day := start.In(location); day.Before(end); day = day.AddDate(0, 0, 1) {
dayStart := time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, location)
dayEnd := dayStart.AddDate(0, 0, 1)
for _, sysOrigin := range r.cfg.Dashboard.SysOrigins {
if err := r.replaceGameMetricDay(ctx, tx, statTimezone, sysOrigin, dayStart, dayEnd); err != nil {
return err
}
}
}
if err := r.rebuildAllPeriodFromDays(ctx, tx, statTimezone); err != nil {
return err
}
if err := r.rebuildAllGamePeriodFromDays(ctx, tx, statTimezone); err != nil {
return err
}
}
return nil
})
})
}