The state is copied by hand, and the proxy waits out a restart
Two-thirds of a ledger replay was structuredClone; a recursive copy of plain data does the same work in a fraction of the time, so a server boot — every ledger replayed — is half as long, and the automaton's lookahead is quicker with it. Caddy now holds a request for up to thirty seconds while the game restarts, dialing every quarter second, so a visitor who lands during a deploy waits instead of meeting a 502. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
0821b8f7c7
commit
c7edfa74ad
@@ -26,8 +26,10 @@ chown -R wizwar:wizwar /opt/wizwar /var/lib/wizwar
|
|||||||
|
|
||||||
# Caddy vhost: auto-TLS, security headers, proxy to the game.
|
# Caddy vhost: auto-TLS, security headers, proxy to the game.
|
||||||
# Access log kept to 30 rolls of 10MiB: the nightly rollup keeps the
|
# Access log kept to 30 rolls of 10MiB: the nightly rollup keeps the
|
||||||
# counts; the raw lines back it for a while.
|
# counts; the raw lines back it for a while. A deploy restarts the game
|
||||||
printf '%s\n\nheader {\n\tStrict-Transport-Security "max-age=31536000"\n\tX-Content-Type-Options "nosniff"\n\tX-Frame-Options "DENY"\n\tReferrer-Policy "no-referrer"\n}\nlog {\n\toutput file /var/lib/caddy/access.log {\n\t\troll_size 10MiB\n\t\troll_keep 30\n\t}\n}\nreverse_proxy localhost:8787\n' "$HOST" > /etc/caddy/Caddyfile
|
# for a few seconds; the proxy holds requests that land in that gap and
|
||||||
|
# keeps dialing, so a visitor waits instead of meeting a 502.
|
||||||
|
printf '%s\n\nheader {\n\tStrict-Transport-Security "max-age=31536000"\n\tX-Content-Type-Options "nosniff"\n\tX-Frame-Options "DENY"\n\tReferrer-Policy "no-referrer"\n}\nlog {\n\toutput file /var/lib/caddy/access.log {\n\t\troll_size 10MiB\n\t\troll_keep 30\n\t}\n}\nreverse_proxy localhost:8787 {\n\tlb_try_duration 30s\n\tlb_try_interval 250ms\n}\n' "$HOST" > /etc/caddy/Caddyfile
|
||||||
systemctl reload caddy
|
systemctl reload caddy
|
||||||
|
|
||||||
# Firewall: ssh + web only. The game server binds loopback and is reached
|
# Firewall: ssh + web only. The game server binds loopback and is reached
|
||||||
|
|||||||
@@ -4068,8 +4068,22 @@ export function activePlayer(state: GameState): PlayerState {
|
|||||||
return state.players[state.turn.activeIndex]!;
|
return state.players[state.turn.activeIndex]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The state is plain data — literals, arrays, numbers (Infinity
|
||||||
|
* included), strings, booleans, and the odd undefined — so a recursive
|
||||||
|
* copy serves, and runs several times faster than structuredClone. Every
|
||||||
|
* command clones once, and a server boot replays every ledger. */
|
||||||
function clone(state: GameState): GameState {
|
function clone(state: GameState): GameState {
|
||||||
return structuredClone(state);
|
return deepCopy(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deepCopy<T>(value: T): T {
|
||||||
|
if (Array.isArray(value)) return value.map(deepCopy) as T;
|
||||||
|
if (value !== null && typeof value === "object") {
|
||||||
|
const out: Record<string, unknown> = {};
|
||||||
|
for (const key in value) out[key] = deepCopy((value as Record<string, unknown>)[key]);
|
||||||
|
return out as T;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Everything an eliminated wizard leaves behind goes with them.
|
/** Everything an eliminated wizard leaves behind goes with them.
|
||||||
|
|||||||
Reference in New Issue
Block a user