Skip to main content

ADR-0024: Viewed fixtures outrank in-play fixtures in Betfair stream cap truncation

Date: 2026-07-29 Status: Accepted

Context

A single Betfair stream subscription is hard-capped at 200 markets (MAX_MARKETS_PER_SUBSCRIPTION, BetfairStreamClient). When classified demand exceeds the cap, StreamManager.desiredMarketMembership truncates at fixture granularity by priority tier. The original tier order was IN-PLAY (1) > VIEWED (2) > rest (3).

On 2026-07-29 prod carried ~191 baseline in-play markets (20 live soccer + 13 tennis fixtures). A client actively viewing and betting The Hundred fixture 35871459 (MI London v London Spirit) pushed demand to 204–207; truncation skipped exactly that fixture because it ranked below unwatched in-play soccer. Result: frozen exchange odds on the client's screen, and bets placed at stale prices that lapsed (2 orders) or sat unmatched for up to ~25 minutes. The in-play discovery poll (listMarketCatalogue, inPlayOnly, maxResults: 200, FIRST_TO_START) is itself saturated on such evenings, so the cricket fixture never enters the in-play tracked set and can only stream via viewer interest — which the old ordering then sacrificed first.

Decision

Viewed fixtures (refCount > 0 — a player has the fixture open over WebSocket) are ALWAYS the top truncation tier. In-play fixtures come second. Grace/rest remain third. Within a tier the ordering is unchanged: earliest subscribedAt, then fixtureId. Whole-fixture greedy truncation is unchanged.

A fixture that is both viewed and in-play ranks in tier 1 (refCount is checked first).

Consequences

  • A fixture a player is actually looking at can no longer be displaced from the stream by unwatched in-play fixtures; live prices follow the player.
  • Under sustained over-cap demand, enough concurrent viewers on distinct fixtures can displace ALL unviewed in-play fixtures. Odds/volume logging to TimescaleDB (fraud detection) pauses for displaced fixtures while demand stays over the cap. Accepted: player-facing correctness beats background logging coverage.
  • The residual pressures are NOT addressed here and remain follow-ups: the 200-market stream cap itself, in-play poll saturation (cricket never auto-streams on busy soccer evenings), per-fixture market budgeting, and multi-connection streaming.