pub struct RestLimits {Show 15 fields
pub max_sessions: usize,
pub max_one_shot_concurrency: usize,
pub max_session_call_concurrency: usize,
pub max_session_call_concurrency_per_session: usize,
pub max_poll_timeout: Duration,
pub min_stream_poll_timeout: Duration,
pub max_text_turn_duration: Duration,
pub max_text_turn_output_bytes: usize,
pub max_request_body_bytes: usize,
pub pending_request_ttl: Duration,
pub max_pending_requests_per_session: usize,
pub events_channel_capacity: usize,
pub idle_session_ttl: Duration,
pub compatibility_ttl: Duration,
pub sse_keep_alive_interval: Duration,
}Expand description
Resource limits used by the default REST backend and route layer.
Every field has a hardcoded default (below) and can be overridden
independently via a CODEX_APP_SERVER_REST_* environment variable
through RestLimits::from_env / RestLimits::try_from_env. A
variable that is absent falls back to the field’s default; a variable
that is present but fails to parse is a hard error
(RestLimitsEnvError), never a silent fallback - a malformed override
that quietly reverts to the default is exactly how an operator ships a
10x-wrong limit and never notices.
| Field | Env var | Default |
|---|---|---|
max_sessions | CODEX_APP_SERVER_REST_MAX_SESSIONS | 16 |
max_one_shot_concurrency | CODEX_APP_SERVER_REST_MAX_ONE_SHOT_CONCURRENCY | 4 |
max_session_call_concurrency | CODEX_APP_SERVER_REST_MAX_SESSION_CALL_CONCURRENCY | 64 |
max_session_call_concurrency_per_session | CODEX_APP_SERVER_REST_MAX_SESSION_CALL_CONCURRENCY_PER_SESSION | 8 |
max_poll_timeout | CODEX_APP_SERVER_REST_MAX_POLL_TIMEOUT_MS | 30000 (30s) |
min_stream_poll_timeout | CODEX_APP_SERVER_REST_MIN_STREAM_POLL_TIMEOUT_MS | 250 |
max_text_turn_duration | CODEX_APP_SERVER_REST_MAX_TEXT_TURN_DURATION_MS | 600000 (10m) |
max_text_turn_output_bytes | CODEX_APP_SERVER_REST_MAX_TEXT_TURN_OUTPUT_BYTES | 1048576 (1 MiB) |
max_request_body_bytes | CODEX_APP_SERVER_REST_MAX_REQUEST_BODY_BYTES | 2097152 (2 MiB) |
pending_request_ttl | CODEX_APP_SERVER_REST_PENDING_REQUEST_TTL_MS | 600000 (10m) |
max_pending_requests_per_session | CODEX_APP_SERVER_REST_MAX_PENDING_REQUESTS_PER_SESSION | 64 |
events_channel_capacity | CODEX_APP_SERVER_REST_EVENTS_CHANNEL_CAPACITY | 1024 |
idle_session_ttl | CODEX_APP_SERVER_REST_IDLE_SESSION_TTL_MS | 1800000 (30m) |
compatibility_ttl | CODEX_APP_SERVER_REST_COMPATIBILITY_TTL_MS | 30000 (30s) |
sse_keep_alive_interval | CODEX_APP_SERVER_REST_SSE_KEEP_ALIVE_MS | 15000 (15s) |
Fields§
§max_sessions: usizeMaximum number of concurrently open stateful bridge sessions
(POST /v1/sessions). Enforced both by a semaphore in
crate::rest::CodexRestBackend and by an explicit pre-check in the
route handler (so a full backend rejects before spawning a process).
Env: CODEX_APP_SERVER_REST_MAX_SESSIONS. Default: 16.
max_one_shot_concurrency: usizeMaximum number of one-shot requests (POST /v1/text-turn,
POST /v1/call/{method}) running at once; each spawns its own
short-lived Codex process. Env:
CODEX_APP_SERVER_REST_MAX_ONE_SHOT_CONCURRENCY. Default: 4.
max_session_call_concurrency: usizeMaximum number of in-flight POST /v1/sessions/{sessionId}/call/*
calls across all sessions combined. Env:
CODEX_APP_SERVER_REST_MAX_SESSION_CALL_CONCURRENCY. Default: 64.
max_session_call_concurrency_per_session: usizeMaximum number of in-flight POST /v1/sessions/{sessionId}/call/*
calls for a single session. Env:
CODEX_APP_SERVER_REST_MAX_SESSION_CALL_CONCURRENCY_PER_SESSION.
Default: 8.
max_poll_timeout: DurationUpper bound on ?timeoutMs= for both
GET /v1/sessions/{sessionId}/events and
GET /v1/sessions/{sessionId}/events/stream; a larger requested
value is clamped down to this. Env:
CODEX_APP_SERVER_REST_MAX_POLL_TIMEOUT_MS. Default: 30000 (30s).
min_stream_poll_timeout: DurationLower bound on ?timeoutMs= for GET /v1/sessions/{sessionId}/events/stream only; a smaller requested value
is clamped up to this.
The long-poll route has no floor on purpose (timeoutMs=0 there is a
legitimate “is anything waiting right now?” non-blocking poll, paced by
one HTTP round trip per call). A stream has no such pacing and no use
for a zero timeout, so without a floor one request can drive an
unbounded run of back-to-back backend polls. Costs real events nothing:
the timeout only bounds the idle wait, so this just caps how often an
idle stream emits timeout frames. Env:
CODEX_APP_SERVER_REST_MIN_STREAM_POLL_TIMEOUT_MS. Default: 250.
max_text_turn_duration: DurationWall-clock budget for POST /v1/text-turn to reach a terminal turn
state; the turn is interrupted and the request fails with
RestError::TimedOut past this point. Env:
CODEX_APP_SERVER_REST_MAX_TEXT_TURN_DURATION_MS. Default:
600000 (10m).
max_text_turn_output_bytes: usizeByte cap on accumulated turn output for POST /v1/text-turn; the
turn is interrupted and the request fails with
RestError::PayloadTooLarge past this point. This is the
response-byte-cap knob for the REST layer - the crate has no other
hardcoded response size limit to promote (see the rest
implementation notes for what was audited). Env:
CODEX_APP_SERVER_REST_MAX_TEXT_TURN_OUTPUT_BYTES. Default:
1048576 (1 MiB).
max_request_body_bytes: usizeCap on the size of a request body, applied to every route via axum’s
DefaultBodyLimit. A request whose body exceeds this is rejected with
413 Payload Too Large before any handler runs.
This is the input-side counterpart to
Self::max_text_turn_output_bytes: without it, the only bound on an
incoming prompt or raw-call params object is axum’s own silent 2 MiB
default, which is neither documented nor tunable. Making it an explicit
RestLimits field keeps the “every limit has a default and an env
override” contract true on the request side too. Env:
CODEX_APP_SERVER_REST_MAX_REQUEST_BODY_BYTES. Default: 2097152
(2 MiB, matching axum’s historical default).
pending_request_ttl: DurationHow long a server-originated request surfaced by
GET /v1/sessions/{sessionId}/events(/stream) stays answerable via
POST .../requests/{requestKey}/result or .../error before it
expires with RestError::Gone (also capped by the app-server’s
own reply deadline for that request, whichever is sooner). Env:
CODEX_APP_SERVER_REST_PENDING_REQUEST_TTL_MS. Default: 600000
(10m).
max_pending_requests_per_session: usizeMaximum number of not-yet-replied-to server requests a single
session will hold at once; beyond this, new ones are rejected
(with a JSON-RPC error sent back to the app-server on the caller’s
behalf) rather than buffered without bound. Env:
CODEX_APP_SERVER_REST_MAX_PENDING_REQUESTS_PER_SESSION. Default:
64.
events_channel_capacity: usizeCapacity of each REST-spawned session’s internal event channel -
exactly the channel documented on crate::EventStream, applied via
crate::SessionOptions::with_events_capacity to every session this
backend spawns (POST /v1/text-turn, POST /v1/sessions, and
session-less POST /v1/call/{method}). REST/SSE consumers reading
events over a network are exactly the “slow or stalled consumer” case
that channel’s bound and drop policy exist for: notifications are
dropped once it’s full, but server-originated requests always get a
fallback error reply first rather than being lost - see
crate::EventStream’s doc comment for the exact per-variant policy.
A 0 value is rejected when the session is actually spawned (see
crate::CodexAppServerClient::spawn_with_events_capacity), not
silently accepted here. Env:
CODEX_APP_SERVER_REST_EVENTS_CHANNEL_CAPACITY. Default: 1024
(matching DEFAULT_EVENTS_CHANNEL_CAPACITY).
idle_session_ttl: DurationHow long a stateful bridge session may sit with no in-flight
operation before it is pruned (and its codex app-server process
torn down) on the next backend access. Env:
CODEX_APP_SERVER_REST_IDLE_SESSION_TTL_MS. Default: 1800000
(30m).
compatibility_ttl: DurationHow long a GET /v1/compatibility result is cached before the next
call re-runs the (blocking, codex --version-invoking) check. Env:
CODEX_APP_SERVER_REST_COMPATIBILITY_TTL_MS. Default: 30000
(30s).
sse_keep_alive_interval: DurationInterval between SSE keep-alive frames sent by
GET /v1/sessions/{sessionId}/events/stream while no real event is
ready. Passed straight through to axum’s
KeepAlive::interval.
Env: CODEX_APP_SERVER_REST_SSE_KEEP_ALIVE_MS. Default: 15000
(15s, matching axum’s own KeepAlive default - set explicitly here
rather than relied upon, so this crate’s behavior doesn’t silently
change if axum’s default ever does).
Implementations§
Source§impl RestLimits
impl RestLimits
Sourcepub fn from_env() -> Self
pub fn from_env() -> Self
Builds RestLimits from CODEX_APP_SERVER_REST_* environment
variables, using RestLimits::default for any variable that is
absent.
§Panics
Panics (via RestLimitsEnvError’s Display) if any
CODEX_APP_SERVER_REST_* variable is set but fails to parse. See
RestLimits::try_from_env to handle that case without a panic -
this constructor exists for the common case of one-shot process
startup, where a malformed limit should abort startup loudly rather
than be silently downgraded to the default or handled by caller
code that has to remember to check.
Sourcepub fn try_from_env() -> Result<Self, RestLimitsEnvError>
pub fn try_from_env() -> Result<Self, RestLimitsEnvError>
Builds RestLimits from CODEX_APP_SERVER_REST_* environment
variables, using RestLimits::default for any variable that is
absent, and returning RestLimitsEnvError for the first variable
that is present but fails to parse.
Trait Implementations§
Source§impl Clone for RestLimits
impl Clone for RestLimits
Source§fn clone(&self) -> RestLimits
fn clone(&self) -> RestLimits
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more