fix(multiplayer): use locked rating for season rollover

This commit is contained in:
Josh Creek
2026-09-01 21:32:34 +01:00
parent 96f311c129
commit 3151e54ab3
3 changed files with 26 additions and 15 deletions
+17 -8
View File
@@ -28,16 +28,24 @@ WHERE player_id = $1`
// retry after a worker failure cannot apply compression twice or leave a
// marker without its corresponding rating snapshot.
func ApplyRankedSeasonRollover(ctx context.Context, db *sql.DB, playerID, seasonID string, profile domain.RankedProfile, now time.Time) (domain.RankedProfile, bool, error) {
if playerID == "" {
return domain.RankedProfile{}, false, fmt.Errorf("player ID is required")
}
updated, _, err := domain.ApplySeasonRollover(profile, seasonID)
if err != nil {
return domain.RankedProfile{}, false, err
if db == nil || playerID == "" || seasonID == "" || now.IsZero() {
return domain.RankedProfile{}, false, fmt.Errorf("invalid season rollover arguments")
}
// The caller's profile is only a validation-compatible hint. The durable
// row is authoritative because a result update may have committed after the
// caller read its snapshot but before this transaction acquired the lock.
_ = profile
var updated domain.RankedProfile
applied := false
err = RunSerializable(ctx, db, DefaultSerializableAttempts, func(ctx context.Context, tx *sql.Tx) error {
if _, err := tx.ExecContext(ctx, SeasonRatingLockSQL, playerID); err != nil {
err := RunSerializable(ctx, db, DefaultSerializableAttempts, func(ctx context.Context, tx *sql.Tx) error {
var locked domain.RankedProfile
var revision int64
if err := tx.QueryRowContext(ctx, SeasonRatingLockSQL, playerID).Scan(&locked.Value, &locked.RD, &locked.Volatility, &locked.RankedGames, &revision); err != nil {
return err
}
var err error
updated, _, err = domain.ApplySeasonRollover(locked, seasonID)
if err != nil {
return err
}
result, err := tx.ExecContext(ctx, SeasonRolloverInsertSQL, playerID, seasonID, updated.Value, updated.RD, updated.Volatility, updated.RankedGames, now)
@@ -49,6 +57,7 @@ func ApplyRankedSeasonRollover(ctx context.Context, db *sql.DB, playerID, season
return err
}
if changed == 0 {
updated = locked
return nil
}
if _, err := tx.ExecContext(ctx, SeasonRatingUpdateSQL, playerID, updated.Value, updated.RD, updated.Volatility, now); err != nil {