601970b028
Three-stage refactor of the game-engine plumbing (game logic untouched): Stage 1 — lock-free persistence + admin serialisation. Remove the file lock from repo/fs (the .lock file, the Read/Write-vs-*Safe duality and the dead ReadSafe polling) and replace the two-step rename with a single atomic rename so concurrent reads are torn-free without a lock. Serialise the state-mutating admin writers (init/turn/banish) with one shared router LimitMiddleware, rewritten to block on the request context instead of a racy shared 100ms timer. Stage 2 — remove the obsolete immediate-command path end to end. Players submit through PUT /api/v1/order; the legacy PUT /api/v1/command path is deleted across game (route, handler, 24 command factories, Ctrl), backend (Commands handler/route, engineclient.ExecuteCommands), gateway (dispatch + executeUserGamesCommand + routing entry), the FlatBuffers/model contract (UserGamesCommand[Response]) and transcoder, plus every affected OpenAPI/README/FUNCTIONAL/ARCHITECTURE doc. The integration proxy test is converted to the order path. Stage 3 — flatten the REST->engine wrapper. Replace the executor adapter, the controller package functions and RepoController with one concrete controller.Service; drop the single-implementation Repo and Storage interfaces (repo.Repo / fs.FS are now concrete). Handlers depend on a thin handler.Engine seam and own the domain->REST projection; storage is resolved once at startup instead of per request. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
65 lines
2.9 KiB
Go
65 lines
2.9 KiB
Go
package runtime
|
|
|
|
import "errors"
|
|
|
|
// Sentinel errors. Handlers map them to the standard JSON envelope at
|
|
// the wire boundary; lobby and admin packages observe them through
|
|
// errors.Is when they need to branch on the domain reason.
|
|
var (
|
|
// ErrNotFound is returned when no row matches the requested
|
|
// primary key (engine version, runtime record, player mapping).
|
|
ErrNotFound = errors.New("runtime: not found")
|
|
|
|
// ErrInvalidInput reports request-level validation failures
|
|
// (empty fields, malformed semver, unknown enum values).
|
|
ErrInvalidInput = errors.New("runtime: invalid input")
|
|
|
|
// ErrConflict reports that the requested action conflicts with
|
|
// the current persisted state (illegal status transition, retry
|
|
// while a job is still in-flight, race against the reconciler).
|
|
ErrConflict = errors.New("runtime: conflict")
|
|
|
|
// ErrEngineVersionTaken means a duplicate primary key was
|
|
// observed when registering a new engine version row.
|
|
ErrEngineVersionTaken = errors.New("runtime: engine version already registered")
|
|
|
|
// ErrEngineVersionDisabled reports that a referenced engine
|
|
// version row exists but is marked disabled.
|
|
ErrEngineVersionDisabled = errors.New("runtime: engine version disabled")
|
|
|
|
// ErrPatchSemverIncompatible reports that an admin-requested
|
|
// version patch crosses major or minor boundary, which Galaxy
|
|
// disallows for in-place patching (per ARCHITECTURE.md §9).
|
|
ErrPatchSemverIncompatible = errors.New("runtime: patch must stay inside the same major/minor line")
|
|
|
|
// ErrJobQueueFull reports that the worker pool's buffered job
|
|
// channel is at capacity. Surfaced as 503 service_unavailable at
|
|
// the wire boundary; in practice the pool size and queue depth
|
|
// are budgeted in `BACKEND_RUNTIME_*` env vars so the operator
|
|
// can absorb peaks.
|
|
ErrJobQueueFull = errors.New("runtime: job queue full")
|
|
|
|
// ErrShutdown means the runtime service has stopped accepting
|
|
// work because the parent context was cancelled.
|
|
ErrShutdown = errors.New("runtime: shutting down")
|
|
|
|
// ErrTurnAlreadyClosed reports that the runtime is currently
|
|
// producing a turn — runtime status is `generation_in_progress`
|
|
// — and the engine is not accepting writes for the closing
|
|
// turn. Handlers map this to HTTP 409 with httperr code
|
|
// `turn_already_closed`; the UI shows a conflict banner and
|
|
// waits for the next `game.turn.ready` push.
|
|
ErrTurnAlreadyClosed = errors.New("runtime: turn already closed")
|
|
|
|
// ErrGamePaused reports that the game is not in a state that
|
|
// accepts user-games orders: the runtime row
|
|
// carries `paused = true`, or the runtime status lands on any
|
|
// terminal value (`engine_unreachable`, `generation_failed`,
|
|
// `stopped`, `finished`, `removed`), or the game has not yet
|
|
// finished bootstrapping (`starting`). Handlers map this to
|
|
// HTTP 409 with httperr code `game_paused`; the UI surfaces a
|
|
// pause banner and waits for an admin resume or a fresh
|
|
// snapshot.
|
|
ErrGamePaused = errors.New("runtime: game paused")
|
|
)
|