Skip to content

Troubleshoot a Fleet

Capture router and engine state

Before changing router or engine state, collect a separate bundle for each router in the incident. Choose a fresh output path and select the fleet configuration and run directory that belong to that router.

mkdir -p runs/diagnostics
narwhal diagnostics collect \
  --router http://router:8000 \
  --fleet config/fleet.json \
  --run runs/dev/run-example \
  --out runs/diagnostics/router-incident-001

The diagnostic bundle manifest records HTTP status, retained response bodies, collection errors, source paths and artifact hashes. Exit 3 identifies a partial bundle; inspect its source rows before retrying individual reads. Add --artifact PATH for ingress and supervisor status, engine boot logs, profiles or deployment load results outside the selected run. Use --include-request-content when the incident requires journal or completion content.

For an installation awaiting the collector command, capture the endpoints with bounded curl requests into a private directory:

umask 077
mkdir -p runs/diagnostics
incident_dir=$(mktemp -d runs/diagnostics/router.XXXXXX)

for endpoint in health ready narwhal/state narwhal/lifecycle metrics; do
  name=${endpoint##*/}
  curl --connect-timeout 2 --max-time 5 -sS \
    -o "$incident_dir/$name.body" -w '%{http_code}\n' \
    "http://router:8000/$endpoint" > "$incident_dir/$name.status"
done

Place site-filtered local artifacts beside these manual snapshots. Before stopping an engine, capture the evidence required by its planned lifecycle restart or unplanned-failure procedure.

Router, admission, and lifecycle signals

Signal Next check or action
Request to /health fails Query peer /ready to identify the lease holder; inspect the router process, host, and network path.
/health reports standby Send traffic and lifecycle actions to the active lease holder.
/health reports fenced Identify the current lease holder and remove the fenced router from the load balancer.
/health reports maintenance Follow /narwhal/lifecycle through the engine wave until readiness returns.
Both routers return HTTP 503 from /ready Compare refusal reasons, then inspect backend health, lifecycle holds, monitoring, lease ownership, and handoff freshness.
HTTP 429 increases Separate rejected, refused, and queue-shed reasons before changing capacity.
HTTP 502 increases Inspect engine failures, ejection, quarantine, and in-flight work.
HTTP 504 increases Separate queue and request expiry from engine timeouts using the response error and terminal journal row.
A stream terminates with an error frame Inspect failed attempts, final outcome, and participating engines after the HTTP 200 response has started.
Lifecycle state is blocked Repair the failed drain identity capture or readmission check, then retry that operation.

Continue with the procedure for the affected path:

Fleet overload with healthy engines

Read admission, serving, resident, and pool load from /narwhal/state to trace overload to immediate concurrency rejection, queue-full shedding, queue expiry, or predictive refusal.

When reconciling load-test attainment, divide router completions by admitted requests and client successes by all offered requests, including predictive refusals.

Reduce offered traffic at ingress or add a fleet whose deployment passed validation.

Run the same request mix at two offered rates. Keep serving.max_connections, queue depth, and timeouts fixed, then compare completed throughput and SLO-qualified requests. Use that comparison before raising a limit that could hold work past its TTFT budget.

After recovery

Run the release and production drills after the repair.