feat(loyalty): Google Wallet production readiness — 10 hardening items
Some checks failed
Some checks failed
- Fix rate limiter to extract real client IP and handle sync/async endpoints - Rate-limit public enrollment (10/min) and program info (30/min) endpoints - Add 409 Conflict to non-retryable status codes in retry decorator - Cache private key in get_save_url() to avoid re-reading JSON per call - Make update_class() return bool success status with error-level logging - Move Google Wallet config from core to loyalty module config - Document time.sleep() safety in retry decorator (threadpool execution) - Add per-card retry (1 retry, 2s delay) to wallet sync task - Add logo URL reachability check (HEAD request) to validate_config() - Add 26 comprehensive unit tests for GoogleWalletService Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -66,20 +66,38 @@ def sync_wallet_passes() -> dict:
|
||||
|
||||
google_synced = 0
|
||||
apple_synced = 0
|
||||
failed_card_ids = []
|
||||
|
||||
for card in cards:
|
||||
try:
|
||||
results = wallet_service.sync_card_to_wallets(db, card)
|
||||
if results.get("google_wallet"):
|
||||
google_synced += 1
|
||||
if results.get("apple_wallet"):
|
||||
apple_synced += 1
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to sync card {card.id} to wallets: {e}")
|
||||
synced = False
|
||||
for attempt in range(2): # 1 retry
|
||||
try:
|
||||
results = wallet_service.sync_card_to_wallets(db, card)
|
||||
if results.get("google_wallet"):
|
||||
google_synced += 1
|
||||
if results.get("apple_wallet"):
|
||||
apple_synced += 1
|
||||
synced = True
|
||||
break
|
||||
except Exception as e:
|
||||
if attempt == 0:
|
||||
logger.warning(
|
||||
f"Failed to sync card {card.id} (attempt 1/2), "
|
||||
f"retrying in 2s: {e}"
|
||||
)
|
||||
import time
|
||||
time.sleep(2)
|
||||
else:
|
||||
logger.error(
|
||||
f"Failed to sync card {card.id} after 2 attempts: {e}"
|
||||
)
|
||||
if not synced:
|
||||
failed_card_ids.append(card.id)
|
||||
|
||||
logger.info(
|
||||
f"Wallet sync complete: {len(cards)} cards checked, "
|
||||
f"{google_synced} Google, {apple_synced} Apple"
|
||||
f"{google_synced} Google, {apple_synced} Apple, "
|
||||
f"{len(failed_card_ids)} failed"
|
||||
)
|
||||
|
||||
return {
|
||||
@@ -87,6 +105,7 @@ def sync_wallet_passes() -> dict:
|
||||
"cards_checked": len(cards),
|
||||
"google_synced": google_synced,
|
||||
"apple_synced": apple_synced,
|
||||
"failed_card_ids": failed_card_ids,
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user