mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 00:14:00 +00:00
feat: add ranked season maintenance role
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cosmic-clash/cosmic-clash/server/domain"
|
||||
)
|
||||
|
||||
const DueSeasonRolloversSQL = `SELECT s.season_id, r.player_id, r.rating, r.deviation,
|
||||
r.volatility, r.ranked_games
|
||||
FROM seasons s
|
||||
CROSS JOIN ratings r
|
||||
LEFT JOIN ranked_season_rollovers rr ON rr.season_id = s.season_id AND rr.player_id = r.player_id
|
||||
WHERE s.playlist = 'ranked' AND s.ends_at <= $1 AND rr.player_id IS NULL
|
||||
ORDER BY s.ends_at, s.season_id, r.player_id
|
||||
LIMIT $2`
|
||||
|
||||
const MarkSeasonRolledOverSQL = `UPDATE seasons SET rolled_over_at = $2
|
||||
WHERE season_id = $1 AND rolled_over_at IS NULL
|
||||
AND NOT EXISTS (SELECT 1 FROM ratings r
|
||||
LEFT JOIN ranked_season_rollovers rr ON rr.season_id = $1 AND rr.player_id = r.player_id
|
||||
WHERE rr.player_id IS NULL)`
|
||||
|
||||
type dueSeasonRollover struct {
|
||||
seasonID string
|
||||
playerID string
|
||||
profile domain.RankedProfile
|
||||
}
|
||||
|
||||
// RolloverDueSeasons processes a bounded batch. Each player update is its own
|
||||
// exactly-once SERIALIZABLE transaction, so a worker crash can safely resume.
|
||||
func RolloverDueSeasons(ctx context.Context, db *sql.DB, now time.Time, limit int) (int, error) {
|
||||
if db == nil || now.IsZero() || limit < 1 || limit > 1000 {
|
||||
return 0, fmt.Errorf("invalid season maintenance arguments")
|
||||
}
|
||||
rows, err := db.QueryContext(ctx, DueSeasonRolloversSQL, now, limit)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var due []dueSeasonRollover
|
||||
for rows.Next() {
|
||||
var item dueSeasonRollover
|
||||
if err := rows.Scan(&item.seasonID, &item.playerID, &item.profile.Value, &item.profile.RD, &item.profile.Volatility, &item.profile.RankedGames); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
due = append(due, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
count := 0
|
||||
for _, item := range due {
|
||||
if _, applied, err := ApplyRankedSeasonRollover(ctx, db, item.playerID, item.seasonID, item.profile, now); err != nil {
|
||||
return count, err
|
||||
} else if applied {
|
||||
count++
|
||||
}
|
||||
if _, err := db.ExecContext(ctx, MarkSeasonRolledOverSQL, item.seasonID, now); err != nil {
|
||||
return count, err
|
||||
}
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
Reference in New Issue
Block a user