Backfill
A running match has open slots: someone disconnected, or it started under-full.
sequenceDiagram
autonumber
participant GS as Game Server
participant GB as Game Backend
participant IM as IVK Match
actor NP as New Player
Note over GS: A player leaves, 2 slots open
GS->>GB: report_open_slots(match_id, 2)
GB->>IM: CreateBackfillRequest(queue_id, match_id,<br/>ruleset_id, slots_requested=2, engine_input)
IM-->>GB: backfill_id
NP->>GB: queue_matchmaking(...)
GB->>IM: CreateTicket(...)
IM->>IM: backfill stage assigns tickets to the request
IM->>GB: outcome: backfill.created<br/>{ request, assigned_tickets }
GB-->>NP: game_found { address, port }
NP->>GS: connect
Note over GS: Match is full again
GS->>GB: report_full(match_id)
GB->>IM: CancelBackfillRequests(queue_id, [backfill_id])
The game server reports to the game backend, not to IVK Match. The boundary is the same as everywhere else: only the game backend calls the matchmaker.
What to know
Section titled “What to know”Re-posting is safe and avoids tracking state. A new request for the same match_id
replaces the previous one, so a running server can re-post its current open-slot count on a
timer instead of tracking whether it already has a request outstanding and by how much it has
changed.
ruleset_id is required whenever the queue has more than one ruleset. There is no sensible
default, so a missing one is rejected rather than guessed. Omit it only in single-ruleset queues.
The outcome is self-describing. Backfill.request echoes the original request in full, so no
separate lookup is needed to determine which match the new players belong to.
Cancel when the match fills or ends. Otherwise the request sits until
backfill_requests.expiration_ttl_secs elapses and emits backfill.expired. This causes no errors, but
the matchmaker spends that time trying to fill a match that no longer needs players.