fix: address PR #177 review — move import os to top-level, add audit idempotency guard
- Move `import os` from inside evaluate_game() to module top-level imports (lazy imports are only for circular dependency avoidance) - Add get_or_none idempotency guard before RefractorBoostAudit.create() inside db.atomic() to prevent IntegrityError on UNIQUE(card_state, tier) constraint in PostgreSQL when apply_tier_boost is called twice for the same tier - Update atomicity test stub to provide card_state/tier attributes for the new Peewee expression in the idempotency guard Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6a176af7da
commit
7f17c9b9f2
@ -1,3 +1,5 @@
|
||||
import os
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
import logging
|
||||
from typing import Optional
|
||||
@ -307,8 +309,6 @@ async def evaluate_game(game_id: int, token: str = Depends(oauth2_scheme)):
|
||||
logging.warning("Bad Token: [REDACTED]")
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
import os
|
||||
|
||||
from ..db_engine import RefractorCardState, Player, StratPlay
|
||||
from ..services.refractor_boost import apply_tier_boost
|
||||
from ..services.refractor_evaluator import evaluate_card
|
||||
|
||||
@ -667,7 +667,11 @@ def apply_tier_boost(
|
||||
audit_data["battingcard"] = new_card.id
|
||||
else:
|
||||
audit_data["pitchingcard"] = new_card.id
|
||||
_audit_model.create(**audit_data)
|
||||
existing_audit = _audit_model.get_or_none(
|
||||
(_audit_model.card_state == card_state.id) & (_audit_model.tier == new_tier)
|
||||
)
|
||||
if existing_audit is None:
|
||||
_audit_model.create(**audit_data)
|
||||
|
||||
# 8b. Update RefractorCardState — this is the SOLE tier write on tier-up.
|
||||
card_state.current_tier = new_tier
|
||||
|
||||
@ -1115,7 +1115,19 @@ class TestAtomicity:
|
||||
"""
|
||||
|
||||
class _FailingAuditModel:
|
||||
"""Stub that raises on .create() to simulate audit write failure."""
|
||||
"""Stub that raises on .create() to simulate audit write failure.
|
||||
|
||||
Provides card_state/tier attributes for the Peewee expression in the
|
||||
idempotency guard, and get_or_none returns None so it proceeds to
|
||||
create(), which then raises to simulate the failure.
|
||||
"""
|
||||
|
||||
card_state = RefractorBoostAudit.card_state
|
||||
tier = RefractorBoostAudit.tier
|
||||
|
||||
@staticmethod
|
||||
def get_or_none(*args, **kwargs):
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def create(**kwargs):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user