fix(rust): skip servers known down for a link code, hold syncs while offline (F6, F7)
Two findings of the step-2 player walk (2026-09-27, both rigs). F6, option (b) of the org lead (D186): a code no recent issuer holds - every made-up one - was still asked of every other enabled server, and while any of them was down the redeem waited out its whole timeout (12 s on both rigs). The second pass now skips the servers the board poll last saw without a connected game; they count as offline without the wait. Issuers are still asked whatever their state, so a good code on a down server stays "unsure". Live on the walk core: 338 ms with five servers down, 360 ms with a rig stopped as well. F7 (D187): on Carbon a due audit sync went out the moment the sidecar reconnected, 80 s before "Server startup complete". The worldReady hold reads the stored hello, which is the OLD boot's until the poll reads the new one. reasonToSync now also holds while the stored state says the game is not connected (online 0), which the poll writes the moment the server goes away. titleSync already held on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -20,6 +20,7 @@ const core = require('../../core')
|
||||
const db = require('./links.db')
|
||||
const engagement = require('../../engagement/emit')
|
||||
const servers = require('../servers/servers.model')
|
||||
const serversDb = require('../servers/servers.db')
|
||||
const sidecar = require('../../sidecarClient')
|
||||
|
||||
const log = core.logger('links')
|
||||
@@ -213,7 +214,18 @@ async function redeem({ code, userId }) {
|
||||
const settled = asked.find((result) => result.ok || result.reason === 'taken')
|
||||
if (settled) return settled
|
||||
|
||||
const rest = await Promise.all(others.map((server) => confirmOne({ server, code, userId })))
|
||||
// **Not the ones this site already knows are down** (F6, option b of the step-2
|
||||
// walk). In parallel is not enough on its own: while any server is down, a code
|
||||
// no issuer holds — every made-up one — still waited out that server's whole
|
||||
// timeout, twelve seconds on both rigs. A server the poll has seen go down cannot
|
||||
// answer, and it is not an issuer, so it cannot hold the code: it counts as
|
||||
// `offline` without the wait. A server with no state yet is asked.
|
||||
const down = await knownDown()
|
||||
const reachable = others.filter((server) => !down.has(String(server.id)))
|
||||
const rest = [
|
||||
...(await Promise.all(reachable.map((server) => confirmOne({ server, code, userId })))),
|
||||
...others.filter((server) => down.has(String(server.id))).map(() => ({ ok: false, reason: 'offline' })),
|
||||
]
|
||||
const late = rest.find((result) => result.ok || result.reason === 'taken')
|
||||
if (late) return late
|
||||
|
||||
@@ -224,6 +236,20 @@ async function redeem({ code, userId }) {
|
||||
return { ok: false, reason: 'rejected' }
|
||||
}
|
||||
|
||||
/**
|
||||
* The servers the board poll last saw without a connected game, by id. A failed
|
||||
* read is an empty set — everybody is asked, which is slow and never wrong.
|
||||
*/
|
||||
async function knownDown() {
|
||||
try {
|
||||
const states = await serversDb.listState()
|
||||
return new Set(states.filter((state) => !Number(state.online)).map((state) => String(state.serverId)))
|
||||
} catch (err) {
|
||||
log.warn('could not read server state for the link fleet', { error: err.message })
|
||||
return new Set()
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove a link the caller owns. False when they did not hold it. */
|
||||
async function unlinkOwned(steamId, userId) {
|
||||
const removed = (await db.removeOwned(steamId, userId)) > 0
|
||||
|
||||
Reference in New Issue
Block a user