120 lines
2.8 KiB
Go
120 lines
2.8 KiB
Go
package storage
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"time"
|
|
)
|
|
|
|
func (r *MySQLRepository) StartCleanup(ctx context.Context, logger *slog.Logger) {
|
|
if r.cfg.Dashboard.CleanupInterval <= 0 {
|
|
return
|
|
}
|
|
go func() {
|
|
r.cleanupOnce(ctx, logger)
|
|
ticker := time.NewTicker(r.cfg.Dashboard.CleanupInterval)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
r.cleanupOnce(ctx, logger)
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (r *MySQLRepository) cleanupOnce(ctx context.Context, logger *slog.Logger) {
|
|
rows, err := r.Cleanup(ctx)
|
|
if err != nil {
|
|
if r.metrics != nil {
|
|
r.metrics.RecordError(err)
|
|
}
|
|
logger.Error("dashboard cleanup failed", "error", err)
|
|
return
|
|
}
|
|
if r.metrics != nil {
|
|
r.metrics.RecordCleanup(rows)
|
|
}
|
|
if rows > 0 {
|
|
logger.Info("dashboard cleanup finished", "rows", rows)
|
|
}
|
|
}
|
|
|
|
func (r *MySQLRepository) Cleanup(ctx context.Context) (int64, error) {
|
|
var total int64
|
|
if r.cfg.Dashboard.DedupRetention > 0 {
|
|
cutoff := time.Now().Add(-r.cfg.Dashboard.DedupRetention)
|
|
rows, err := r.deleteLimit(ctx, `
|
|
DELETE FROM dashboard_cdc_event_dedup
|
|
WHERE created_at < ?
|
|
LIMIT ?`, cutoff, r.cfg.Dashboard.CleanupBatchSize)
|
|
if err != nil {
|
|
return total, err
|
|
}
|
|
total += rows
|
|
}
|
|
|
|
if r.cfg.Dashboard.UserMetricDays > 0 {
|
|
cutoffDate := time.Now().AddDate(0, 0, -r.cfg.Dashboard.UserMetricDays).Format("2006-01-02")
|
|
deletes := []struct {
|
|
sql string
|
|
args []interface{}
|
|
}{
|
|
{
|
|
sql: `
|
|
DELETE FROM country_dashboard_daily_user_metric
|
|
WHERE stat_date < ?
|
|
LIMIT ?`,
|
|
args: []interface{}{cutoffDate, r.cfg.Dashboard.CleanupBatchSize},
|
|
},
|
|
{
|
|
sql: `
|
|
DELETE FROM country_dashboard_period_user_metric
|
|
WHERE period_type <> 'ALL'
|
|
AND period_end_date IS NOT NULL
|
|
AND period_end_date < ?
|
|
LIMIT ?`,
|
|
args: []interface{}{cutoffDate, r.cfg.Dashboard.CleanupBatchSize},
|
|
},
|
|
{
|
|
sql: `
|
|
DELETE FROM country_dashboard_game_period_user_metric
|
|
WHERE period_type <> 'ALL'
|
|
AND period_end_date IS NOT NULL
|
|
AND period_end_date < ?
|
|
LIMIT ?`,
|
|
args: []interface{}{cutoffDate, r.cfg.Dashboard.CleanupBatchSize},
|
|
},
|
|
{
|
|
sql: `
|
|
DELETE FROM country_dashboard_recharge_detail
|
|
WHERE create_time < ?
|
|
LIMIT ?`,
|
|
args: []interface{}{cutoffDate, r.cfg.Dashboard.CleanupBatchSize},
|
|
},
|
|
}
|
|
for _, item := range deletes {
|
|
rows, err := r.execRows(ctx, item.sql, item.args...)
|
|
if err != nil {
|
|
return total, err
|
|
}
|
|
total += rows
|
|
}
|
|
}
|
|
return total, nil
|
|
}
|
|
|
|
func (r *MySQLRepository) deleteLimit(ctx context.Context, query string, args ...interface{}) (int64, error) {
|
|
return r.execRows(ctx, query, args...)
|
|
}
|
|
|
|
func (r *MySQLRepository) execRows(ctx context.Context, query string, args ...interface{}) (int64, error) {
|
|
result, err := r.db.ExecContext(ctx, query, args...)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected()
|
|
}
|