Skip to content

devlog/api-plumbing/terminal-health-checks-and-safe-model-fallbacks-102.md

Terminal Health Checks and Safe Model Fallbacks

Probe inference, not just the relay hostname

A reachable hostname is not a working model. My deployment check sends a tiny inference request through the same authentication and route the application uses. It checks the HTTP response and generated content before calling the endpoint healthy.

Fluxo keeps the wiring small: one key and one base URL, https://api.fluxorelay.com, across Claude, GPT, Gemini, DeepSeek, Kimi, GLM, Qwen, Grok and more. It works with Claude Code, Codex, Gemini CLI and any OpenAI SDK. Here, curl makes every timeout and fallback decision visible. ([fluxorelay.com](https://fluxorelay.com/))

1. Set two explicit model routes in Bash

Use Bash with curl and jq installed. Run each command paragraph as one line, in the same shell. These examples use GPT-5.6 Sol as primary and GPT-6 Astra as fallback, with their published API identifiers. If you need a key, you can create a Fluxo account before continuing. ([fluxorelay.com](https://fluxorelay.com/))

export FLUXO_BASE='https://api.fluxorelay.com'; export PRIMARY='gpt-5.6-sol'; export FALLBACK='gpt-6-astra'; read -rsp 'Fluxo API key: ' FLUXO_KEY; printf '\n'; export FLUXO_KEY

Keep shell tracing disabled while handling credentials. The Chat Completions route below appends /v1/chat/completions to the relay hostname; Fluxo documents the /v1 SDK base and Chat Completions interface. ([fluxorelay.com](https://fluxorelay.com/))

2. Define a bounded inference probe

The function below uses a private temporary file and emits diagnostics to stderr. Exit zero means usable content, 75 means eligible for our fallback policy, and one means stop. The two-second connection limit and ten-second total limit are starter budgets, not universal latency targets. curl exposes these as separate controls. ([curl.se](https://curl.se/docs/manpage.html))

probe() ( umask 077; body=$(mktemp) || exit 1; trap 'rm -f "$body"' EXIT; payload=$(jq -nc --arg model "$1" '{model:$model,messages:[{role:"user",content:"Reply with OK."}],stream:false}') || exit 1; status=$(curl --silent --show-error --connect-timeout 2 --max-time 10 --output "$body" --write-out '%{http_code}' --header "Authorization: Bearer $FLUXO_KEY" --header 'Content-Type: application/json' --data "$payload" "$FLUXO_BASE/v1/chat/completions"); rc=$?; printf 'model=%s http=%s curl=%s\n' "$1" "$status" "$rc" >&2; case "$rc" in 0) ;; 6|7|28|52|56) exit 75 ;; *) exit 1 ;; esac; case "$status" in 200) jq -er '.choices[0].message.content | select(type == "string") | select(length > 0)' "$body" ;; 408|500|502|503|504) exit 75 ;; *) exit 1 ;; esac; )

probe "$PRIMARY"; probe "$FALLBACK" — This deliberately checks nonempty text rather than exact obedience to “OK.” It is a synthetic availability check, not a quality evaluation. There is no output-token cap here: add the verified, model-supported parameter before scheduling frequent probes.

3. Fall back once, without multiplying retries

Run this wrapper to attempt the secondary only after a failure classified as transient:

( probe "$PRIMARY"; rc=$?; if [ "$rc" -eq 75 ]; then probe "$FALLBACK"; else exit "$rc"; fi )

There are at most two attempts, each bounded by ten seconds. Treat that as an approximately twenty-second network budget, plus local overhead. This command demonstrates routing with synthetic traffic; move the same policy into the application around its actual request.

Authentication, permission and malformed-request failures should stop deployment, not disappear behind another model. OpenAI documents these separately from connection and server failures. Our conservative policy also stops on 429: inspect whether the cause is throttling or exhausted quota before retrying. ([developers.openai.com](https://developers.openai.com/api/docs/guides/error-codes))

When implementing this with an SDK, explicitly control its retry count. Official SDK retries can otherwise combine with application retries and stretch the deadline. Respect Retry-After when adding delayed retries. ([developers.openai.com](https://developers.openai.com/api/reference/typescript?utm_source=openai))

4. Verify failures before enabling automatic routing

  • Inject a primary-only 503 through your staging HTTP stub.
  • Confirm the fallback receives exactly one request before succeeding.
  • Inject authentication failures and confirm no fallback request occurs.
  • Make both routes time out and verify bounded failure.
  • Validate tool schemas and context requirements against both models.
  • Never replay tool side effects after partially streamed responses.

5. Separate scheduled probes from request traffic

For production, run one centralized probe worker rather than one per application replica. Track model, status, latency and fallback rate without recording credentials or prompts. Open a per-model circuit after repeated transient failures, then allow one recovery probe after a cooldown. Keep process liveness independent of upstream availability.

Budget those checks: Fluxo bills real tokens, including cache reads and writes, without a monthly fee. Its referral share applies when invited users pay; it does not change this walkthrough’s failure policy. ([fluxorelay.com](https://fluxorelay.com/))

The useful alert is not merely “the relay responds.” It is “our primary keeps failing, the fallback works, and users remain inside their latency budget.”

Next in the buffer

Sign up in a minute and get credit to try every model mentioned here. Sign up →