When Provisioning Fails
The match is real but you cannot get a server for it. Those players have already left the pool, so doing nothing strands them. Put them back; do not dump them out to the menu.
sequenceDiagram
autonumber
participant IM as IVK Match
participant GB as Your Backend
participant OR as Orchestrator
actor P as Players
IM->>GB: outcome: match.created { match_id, tickets, host }
GB->>OR: CreateGameServer(host = host.preferred)
OR-->>GB: error, capacity exhausted
loop for each host in host.acceptable
GB->>OR: CreateGameServer(host)
OR-->>GB: error
end
Note over GB: No server available on any acceptable host
GB->>IM: ReactivateTickets(queue_id, ticket_ids)
IM-->>GB: failed_ticket_ids: []
Note over IM: Tickets are back in the pool,<br/>keeping their original created_at
GB-->>P: still searching (no error shown)
Three things make this work.
host.acceptable is a fallback list you get for free
Section titled “host.acceptable is a fallback list you get for free”Every host in engine_output.host.acceptable is tolerable to every ticket in the match, not just
some of them. Walk it before giving up. A capacity failure in one region is common; a capacity
failure in every region a match can tolerate is rare.
ReactivateTickets preserves queue position
Section titled “ReactivateTickets preserves queue position”Reactivated tickets keep their original created_at, so a player who already waited 90 seconds does
not go to the back of the line. As far as the player is concerned nothing happened. They were never
told a match was found, and they are still searching.
That is why the player-facing message here is “still searching” rather than an error. The failure is yours to absorb.
terminal_retention_ttl_secs is your compensation window
Section titled “terminal_retention_ttl_secs is your compensation window”A resolved ticket can only be reactivated while it is still retained. Any ticket returned in
failed_ticket_ids was already evicted and needs a fresh CreateTicket instead.
Set pool.tickets.terminal_retention_ttl_secs above your orchestrator’s worst-case provisioning
timeout plus the time it takes to walk the fallback list. The default of 300 s suits most
setups; use 3600 s where provisioning can be slow.
If you get a non-empty failed_ticket_ids, treat it as a signal that the window is too short for
your provisioning path, not just as a one-off.
Do not silently drop the match
Section titled “Do not silently drop the match”Receiving match.created and neither honouring nor compensating for it is never acceptable. Every
other ticket in that match is waiting on you. If your handler crashes mid-provisioning the outcome
will be redelivered, since delivery is at-least-once, so an idempotent handler keyed on Match.id
recovers on its own.