mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-09-19 16:39:15 +00:00
The 446-restart-loop incident: adding a headers block to a source without
removing the source's existing `headers: {}` produced a duplicate YAML key.
The process exited on startup, healthcheck failed, and rollback restored only
the binary — so the old binary kept parsing the same broken config and the
service span in systemd's restart loop. Config was treated as out of scope
for deployment; it is not.
Three changes close the loop:
1. cmd/llmsproxy: new `-check` flag validates a config (parse +
ApplyDefaults) and exits, without starting the Lua VM, touching
runtime.json, or binding a port — safe to run against a live service.
Unlike normal startup it does NOT create a default config, so a missing
file is an error.
2. deploy.sh `--config <file>`: stage a config for deployment, atomically
renamed into place with the same copy->rename(2) technique as the binary.
Omitted means the live config is left alone.
3. Ordering: config replacement and preflight both run BEFORE
restart_service, so an invalid config is caught while the service is still
healthy and never triggers a restart. rollback() now restores binary AND
config (only when this run replaced it, so concurrent WebUI edits survive),
then re-runs -check before restarting — refusing to restart into a config
that still fails, instead of trading one restart storm for another.
Also: the sha256-unchanged early exit now only fires when there is no pending
config, otherwise `--config` would be silently dropped.
Verified on the live deployment:
- reproduced the exact duplicate-key config: preflight caught it, PID
unchanged (zero interruption), binary and config both rolled back, gateway
still answering 200
- valid config: replaced, service restarted, new value live
- no --config: binary-only deploy unaffected
- go test -tags luajit ./... passes