Streaming Responses
Starting with Fission v1.27.0, a function can stream its response incrementally — over Server-Sent Events (SSE), HTTP chunked transfer, or a WebSocket upgrade.
The response flushes to the client as it is produced and is not bound by functionTimeout.
By default, though, a function still buffers its full response and the router cuts the request off at that limit.
Streaming is per-function and opt-in: omit the spec.streaming object (or the --streaming flag) and the function keeps the existing buffered behavior exactly.
Typical use cases are LLM token streaming, AI agent runs, chat, SSE feeds, and other long-running or bidirectional responses.
sequenceDiagram
autonumber
participant C as Client
participant R as Router
participant F as Function Pod
C->>R: HTTP request
R->>F: proxy request
F-->>R: first bytes
R-->>C: flush immediately
Note over R,F: idle timer resets on every chunk
F-->>R: more chunks
R-->>C: flush each chunk
F-->>R: stream ends
R-->>C: close connectionEnable streaming
Create the function with --streaming, add a route, and invoke it:
fission fn create --name chat --env nodejs --code chat.js --streaming
fission route create --name chat --function chat --url /chat --method POST
Toggle streaming back off on an existing function:
fission fn update --name chat --streaming=false
CLI flags
| Flag | Default | Meaning |
|---|---|---|
--streaming | off | Enable streaming responses for the function. Disable on update with --streaming=false. |
--streamingprotocol | auto | Streaming protocol: auto, sse, chunked, or websocket. auto covers all cases; websocket signals intent (the upgrade is detected from the request). |
--streamingidletimeout | 60 | Abort the stream if no bytes flow from the function for this many seconds; reset on each chunk. Also bounds time-to-first-byte. Not applied after a WebSocket upgrade. |
--streamingmaxduration | 0 | Hard ceiling (seconds) on total stream lifetime; 0 means no ceiling. |
How streaming changes timeouts
A streaming function does not inheritfunctionTimeoutas a wall-clock cap — that limit is exactly what streaming exists to escape. Progress is governed by the idle timeout (default 60s, reset on every chunk), and--streamingmaxdurationis the optional absolute ceiling. A function that keeps producing output completes even if it runs far pastfunctionTimeout. See the function timeout concept for how this relates to the buffered path.
Protocols
auto (the default) handles every case.
Set a specific protocol only to signal intent.
Streaming works on both the public HTTPTrigger route and the internal /fission-function/<ns>/<name> invocation path.
With SSE the function writes text/event-stream chunks and the router flushes each one as it arrives.
Use curl -N to watch tokens arrive incrementally instead of all at once:
curl -N https://<router>/chat -d '{"prompt":"hello"}'
Create the function with the websocket protocol and connect with any WebSocket client:
fission fn create --name ws --env nodejs --code ws.js --streaming --streamingprotocol websocket
fission route create --name ws --function ws --url /ws --method GET
wscat -c ws://<router>/ws
WebSocket
WebSocket is now first-class for every environment, not just the Python GEVENT environment.
The router upgrades the connection and holds the function pod for the socket’s whole lifetime (a router-driven keepalive).
The main(ws, clients) programming model is unchanged.
After the 101 upgrade the router pipes bytes both ways and cannot observe idle time, so the idle timeout only bounds the time to upgrade.
Set --streamingmaxduration to bound the socket’s total lifetime.
The legacy Pythonsocket_tracker.pykeepalive mechanism still works but is deprecated in favor of the streaming approach and is targeted for removal in a future release. New environment images should drop calls to the fetcher/wseventendpoints and rely on the streaming WebSocket path.
For a worked WebSocket example, see the WebSocket sample blog post.
Declarative spec
You can enable streaming directly on the Function resource:
apiVersion: fission.io/v1
kind: Function
metadata:
name: chat
spec:
environment:
name: nodejs
streaming:
protocol: sse
idleTimeoutSeconds: 60
maxDurationSeconds: 0 # optional absolute ceiling; 0 = unlimited
Cluster default
The optional router environment variable ROUTER_STREAM_IDLE_TIMEOUT sets the cluster-wide default idle window.
Per-function idleTimeoutSeconds overrides it.
The value is a Go duration string (for example 90s) and must be positive — unlike the per-function flag, which takes integer seconds.
The Helm chart does not surface this variable; set it on the router deployment directly:
kubectl set env deployment/router -n fission ROUTER_STREAM_IDLE_TIMEOUT=90s
Related
- Create and run functions — the everyday function workflow.
- Controlling Function Execution — executors, scaling, and concurrency.
- HTTP Triggers — routing requests to a function.
- Functions — the
Functionresource and the function timeout. - Custom Resource Definition Specification — the
streamingspec fields.