Skip to content

Sessions & caching

Two layers of reuse keep a run from repeating work: sessions cache an actor’s credentials, and step results cache values within a run.

When an actor is first needed, its auth block runs and the extracted values become that actor’s session:

actors/vendor.yaml
name: vendor
auth:
strategy: simple
path: /api/v1/auth/vendor/login
extract:
token: $.data.accessToken
refresh_token: $.data.refreshToken
vendor_id: $.data.user.id
session:
ttl: 15m

For the next 15 minutes that session is reused. A seven-step chain touching three actors performs three logins, not seven — and logins never appear as chain steps, because each one happens inside the step that needed it.

ttl accepts s, m, h, d. Default is 15m.

Match your API’s token lifetime, slightly under it:

Token lifetimeReasonable ttl
1 hour45m
15 minutes10m
Long-lived / static1h or more

Too long and you’ll send expired tokens and get 401s. Too short and you’ll re-authenticate needlessly — which matters if your login endpoint is rate limited.

When a session expires, a refresh block avoids a full re-authentication:

session:
ttl: 15m
refresh:
method: POST
path: /api/v1/auth/refresh
body:
refresh_token: "{{vendor.refresh_token}}"
extract:
token: $.data.accessToken

One request instead of the whole login chain — worth it when login is expensive (OTP, MFA) or rate limited.

Refresh extractions are merged into the existing session rather than replacing it. Above, token is updated while vendor_id and refresh_token survive, so {{vendor.vendor_id}} keeps working. That merge is why you only need to extract what actually changed.

With no expect_status, any 2xx counts as success.

If refresh fails, the step fails with E_SESSION_REFRESH_FAILED. The same code appears when a login fails — including when the server is simply unreachable:

Terminal window
FAIL product.create (0ms) err=E_SESSION_REFRESH_FAILED

So this code means “couldn’t establish this actor’s identity”, not necessarily “the refresh endpoint is broken”. Check the server is up and the credentials are right.

Separately from sessions, the engine won’t repeat an operation whose values it already has. If two branches both need product.create, it runs once and the second appearance is skipped:

Terminal window
OK product.create (113ms) err=—
SK product.create (0ms) err=—

That’s what keeps a wide graph from re-creating the same fixture repeatedly.

When each occurrence must create fresh data:

create:
method: POST
path: /api/v1/orders
force: true

force: true opts that operation out of caching — it executes every time it appears in a chain.

In memory, for the lifetime of the process. A new reqloom run starts with no sessions and authenticates again, so the TTL matters within a run — and in the desktop app, across the operations you click during a working session.

Session values are not written to your project directory, so there’s nothing to gitignore and no token to accidentally commit.

Related but distinct: at the start of a real run, the engine collects the {{secret.X}} names your schema actually references and reads exactly those from the keychain. Not a bulk dump, and not re-read per step.

Dry runs — reqloom lint, and the desktop’s chain preview — skip secret loading entirely, so they never trigger a keychain unlock prompt. Unresolved {{secret.X}} in a preview is expected. See secrets.

Getting 401s partway through a long run. The token expired mid-run. Lower ttl, or add a refresh block.

Every run re-authenticates. Expected — sessions don’t persist between CLI invocations. If login is rate limited, consider a longer-lived credential in the environment for CI rather than a login chain.

E_SESSION_REFRESH_FAILED on the first step. Usually not a session problem at all: the login request itself failed. Check baseUrl, that the server is running, and the credentials.

Values from login are missing. Confirm the auth extract paths match the real response shape. An actor variable that was never extracted resolves to nothing and shows up as E_VAR_UNRESOLVED in whatever used it.