Asynchronous Invocation

Invoke a Fission function fire-and-forget — the router enqueues the call, returns a durable invocation id, and delivers it in the background with retries, a dead-letter queue, and result destinations.

Invoke a function fire-and-forget: the router accepts the call, returns a durable invocation id immediately, and delivers it in the background with retries — so the caller never waits for the work to finish.

A normal invocation is synchronous: the caller holds the connection open until the function returns a response. That is wrong for work that is slow, spiky, or must not be lost if a caller disconnects. Examples: sending email, processing an upload, calling a rate-limited third party. Starting with Fission v1.27.0, an asynchronous invocation hands that work to Fission and returns right away.

The caller sends X-Fission-Invoke-Mode: async (or uses fission fn test --async). The router enqueues the call on the statestore queue and returns 202 Accepted with a durable invocation id. A background worker then delivers it — retrying transient failures, dead-lettering what it cannot deliver, and optionally invoking a destination function with the result.

flowchart TB
  caller["Caller"]:::user -->|"<b>1.</b> request + X-Fission-Invoke-Mode: async"| router["Router"]:::fission
  router -->|"<b>2.</b> enqueue"| queue["Statestore Queue"]:::store
  router -->|"<b>3.</b> 202 + invocation id"| caller
  queue -->|"<b>4.</b> dequeue"| worker["Async Worker"]:::fission
  worker -->|"<b>5.</b> invoke"| pod["Function Pod"]:::pod
  worker -.->|"exhausted / too old"| dlq["Dead-letter Queue"]:::store
  worker -.->|"on success / failure"| dest["Destination Function"]:::pod

  classDef user fill:#ffffff,stroke:#94a3b8,color:#1f2a43
  classDef fission fill:#e8f0fe,stroke:#2d70de,color:#1f2a43
  classDef pod fill:#e6f7f1,stroke:#11a37f,color:#1f2a43,stroke-dasharray:5 3
  classDef store fill:#fff7e0,stroke:#dba514,color:#1f2a43,stroke-dasharray:5 3

Prerequisites

Asynchronous invocation is off by default and needs the statestore for its durable queue:

helm upgrade --install fission fission-charts/fission-all \
  --namespace fission \
  --set statestore.enabled=true \
  --set statestore.mode=embedded \
  --set asyncInvocation.enabled=true

The chart requires an explicit statestore.mode (embedded or external) when the statestore is enabled. Embedded mode is enough to try async invocation. Autoscaling additionally requires statestore.mode=external.

Invoke asynchronously

The CLI sends the async header and prints the durable invocation id instead of waiting for a response:

$ fission fn test --name resize-image --method POST --body '{"path": "photos/cat.jpg"}' --async
Accepted (202)
invocationId: asyncinv/8f2c1a9e4b7d3c2a9f1e6b5d4c3a2b1f

Any HTTP caller can do the same by setting the header on a request to the function’s HTTP trigger:

curl -XPOST -H "X-Fission-Invoke-Mode: async" \
  --data @photo.json \
  http://$FISSION_ROUTER/resize-image
# HTTP/1.1 202 Accepted
# X-Fission-Invocation-Id: asyncinv/8f2c1a9e4b7d3c2a9f1e6b5d4c3a2b1f
# {"invocationId":"asyncinv/8f2c1a9e4b7d3c2a9f1e6b5d4c3a2b1f"}
When authentication is enabled, set FISSION_INTERNAL_AUTH_SECRET so the CLI signs the internal invocation.

Delivery guarantees and retries

The worker retries a failed delivery with exponential backoff until it either succeeds, exhausts the attempt budget, or the invocation gets too old. When either bound is crossed the invocation is moved to the dead-letter queue rather than dropped. Configure the bounds per function on fn create / fn update:

fission fn update --name resize-image \
  --async-retry-max-attempts 3 \
  --async-max-age 1h
FlagMeaning
--async-retry-max-attemptsMaximum delivery attempts before dead-lettering (1 to 3).
--async-max-ageMaximum age of an invocation before dead-lettering, regardless of attempts.
When the function is invoked through a function alias, the invocation is pinned to the version resolved at enqueue time. Retries re-run that same version even if the alias moves or is rolled back in between, so retries stay deterministic.

Result destinations

An async invocation has no caller waiting for its result, so you can route the result to another function in the same namespace:

fission fn update --name resize-image \
  --async-on-success notify-done \
  --async-on-failure alert-oncall
FlagMeaning
--async-on-successSame-namespace function invoked with the result when delivery succeeds.
--async-on-failureSame-namespace function invoked when the invocation is dead-lettered.

To fan the result out to an event topic instead of a single function, use the --async-on-success-topic / --async-on-failure-topic variants. These publish the result to a Fission eventing topic that any number of functions can subscribe to.

Dead-letter queue

Invocations that exhaust their retries or age out land in the dead-letter queue, where you can inspect and act on them:

# List dead-lettered invocations
fission function dlq list

# Inspect one
fission function dlq show --id asyncinv/8f2c1a9e4b7d3c2a9f1e6b5d4c3a2b1f

# Re-drive one back onto the queue, or all of them
fission function dlq redrive --id asyncinv/8f2c1a9e4b7d3c2a9f1e6b5d4c3a2b1f
fission function dlq redrive --all

# Discard every dead-lettered async invocation
fission function dlq purge

A re-driven invocation starts with a fresh attempt budget.

FlagMeaning
--idOperate on a single durable invocation id (show, redrive).
--allRe-drive every dead-lettered invocation (redrive).
--queueTarget queue: empty for async invocations, or an eventing broker egress queue (mq-egress-<type>).
--limitCap the number of entries dlq list returns.

Autoscaling

An opt-in KEDA ScaledObject scales the async workers on the queue backlog. A burst of enqueued work spins up more delivery capacity, then idles back down when the queue drains.

Autoscaling requires statestore.mode=external (Postgres). The KEDA PostgreSQL scaler reads the backlog from the database directly and cannot see the embedded SQLite file. See Statestore.