Skip to main content

Rolling Service

Status

Active

Date

2026-04-28

Owners

  • Platform Backend

Last Verified Commit

56362a7a

Runtime

API + standalone worker

Purpose

rolling_service owns rolling records and the rolling lifecycle:

  • create
  • complete
  • cancel
  • expire
  • retry completion

Primary Entry Points

  • /internal/rolling/*

Protection model:

  • /internal/rolling/* requires X-Internal-Service-Token
  • gateway, admin_service, and promotion_service are the intended callers

Dependencies

  • PostgreSQL
  • Redis
  • wallet_service

Background Work

rolling_worker runs:

  • wallet-event consumer loop
  • rolling outbox publisher
  • expiry scheduler
  • completion retry loop

Owned Data

  • rolling records
  • rolling inbox/outbox state
  • rolling retry and expiry semantics

Events

Emits:

  • ROLLING_COMPLETED
  • ROLLING_CANCELED

Consumes:

  • wallet stream events including:
    • BET_SETTLED_CONFIRMED
    • BET_ROLLED_BACK_CONFIRMED

Health

  • API /health checks DB and Redis
  • rolling_worker readiness is freshness-based across:
    • event consumer loop
    • outbox loop
    • expiry loop
    • completion retry loop

Key Env Vars

  • DATABASE_URL
  • REDIS_URL
  • WALLET_SERVICE_URL
  • MULTI_BRAND_ENFORCEMENT — required; one of off / observe / enforce. Production target is enforce post-Phase-16. Drives multi_brand_enforcement_mode{service="rolling_service"} gauge and the cross-brand reject decision in brand_check.py (rolling_cross_brand_rejected_total).
  • BRAND_SIGNING_KEYrequired in production; HMAC-SHA256 secret used to sign X-Brand-Signature on outbound brand-scoped wallet writes from rolling-completion / cancel paths.
  • INTERNAL_SERVICE_TOKEN_ROLLINGrequired in production; per-caller token presented to wallet when rolling calls it.
  • PER_CALLER_TOKEN_REQUIREDon is the Phase 16 target; activates the legacy-token hard-reject (T4-D-I2) on inbound /internal/rolling/* calls.
  • INTERNAL_SERVICE_TOKEN — legacy single-shared-token; deprecated. Phase 16 release gate requires the bare variant to be absent.
  • ENABLE_EVENT_CONSUMER
  • ENABLE_OUTBOX_POLLER
  • ENABLE_EXPIRY_SCHEDULER
  • ENABLE_COMPLETION_RETRY

Multi-Brand Constraints

Per ADR-009:

  • rolling records, rolling inbox/outbox, and completion/cancel retry state carry brand_id
  • the rolling event consumer reads brand_id from inbound wallet/game outbox payloads and persists it into rolling rows
  • internal rolling routes require X-Brand-Id; mismatched-player-row behavior is gated by MULTI_BRAND_ENFORCEMENT (observe logs + counts and proceeds; enforce rejects)
  • per-brand rolling completion ratios and cancellation policies resolve from brand_config first, then documented global defaults

Tests

  • cd servers_v2/rolling_service && uv run pytest
  • key suites:
    • tests/test_events_health.py
    • tests/test_retry_tasks.py
    • tests/test_wallet_response_compat.py
    • tests/test_outbox_poller.py
    • tests/test_event_consumer_contracts.py
    • tests/test_internal_auth.py