Files
OpenFrontIO/generate-nginx-upstream.sh
T
Evan c55ea6bb5a Mint game ids on the server, randomly route create-game across workers (#4393)
## What

Game creation no longer requires the caller to pick the `gameID` or
compute its owning worker. The client POSTs to a prefix-less
`/api/create_game`; **nginx (prod) and the vite dev proxy randomly route
it to a worker**, which **mints an id that hashes back to itself** and
returns it along with its `workerIndex`.

## Why it stays correct

The minted id still hashes to the creating worker (via the existing
`generateGameIdForWorker`), so everything downstream that derives the
worker from the gameID — websocket connect, share URL, join flow — keeps
working unchanged. The only thing that moved is *who picks the id and
worker*.

## Changes

- **`src/server/Worker.ts`** — factor create into a shared
`createGameForId`; add `POST /api/create_game` (no id) that mints a
self-owned id and returns `gameInfo` + `workerIndex`/`workerPath`. The
existing `POST /api/create_game/:id` stays.
- **`nginx.conf`** — `location = /api/create_game` proxies to a `random`
worker upstream.
- **`generate-nginx-upstream.sh` + `Dockerfile`** — the entrypoint
generates that upstream from `NUM_WORKERS` at container **start** time.
`NUM_WORKERS` isn't known at image build time (the image is built once
and deployed with different env), so it can't be baked into `nginx.conf`
— hence runtime generation of exactly the live worker ports (no
dead-server padding).
- **`vite.config.ts`** — dev-only middleware forwards `POST
/api/create_game` to a random worker. Vite's `http-proxy` can't pick a
per-request random target, so this is a small middleware plugin (same
pattern as the existing `serveProprietaryDir`), registered before the
`/api` proxy.
- **`src/client/HostLobbyModal.ts`** — stop generating the id
client-side; use the server's.

## Behavior change to note

The host's share link used to be copied **instantly** from a
client-generated id. Now the id comes from the server, so the copy waits
one create round-trip — I moved the URL build/copy into the create
`.then` (and kept the failure path that clears the clipboard). Brief
empty-link state in the modal until create resolves.

## Verification

- tsc + eslint clean; full suite green (1543 tests).
- nginx additions validated with `nginx -t` in isolation (the full file
references container-only paths like `/etc/nginx/mime.types`); upstream
+ `proxy_pass` resolve.
- `generate-nginx-upstream.sh` tested with `NUM_WORKERS` set and unset
(defaults to 1).

Not yet exercised live end-to-end (needs a dev-server restart —
`vite.config.ts` + `Worker.ts` changes aren't hot-reloaded).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 17:15:09 -07:00

40 lines
1.2 KiB
Bash
Executable File

#!/bin/sh
# generate-nginx-upstream.sh
#
# Generates the per-worker nginx config from NUM_WORKERS at container start
# (NUM_WORKERS arrives via the runtime env file and is not known when the image
# is built, so it can't be baked into nginx.conf). Emits two things, both in the
# http context, into a single conf.d file:
#
# 1. upstream openfront_workers - random-balanced across the live workers, so
# nginx can spread requests (e.g. POST /api/create_game) without the caller
# knowing the worker count.
# 2. map $worker $worker_port - worker index -> port (3001 + index), so the
# /wN/ locations route without a hand-maintained if-ladder.
#
# Usage: generate-nginx-upstream.sh [output_path]
set -eu
OUT="${1:-/etc/nginx/conf.d/00-workers.conf}"
n="${NUM_WORKERS:-1}"
{
echo 'upstream openfront_workers {'
echo ' random;'
i=0
while [ "$i" -lt "$n" ]; do
echo " server 127.0.0.1:$((3001 + i));"
i=$((i + 1))
done
echo '}'
echo ''
echo 'map $worker $worker_port {'
echo ' default 3001;'
i=0
while [ "$i" -lt "$n" ]; do
echo " $i $((3001 + i));"
i=$((i + 1))
done
echo '}'
} > "$OUT"