Skip to main content
Reintersect waits up to 30 seconds for a command or message action to answer. When the work takes longer, defer answers the delivery at once and sends your answer when the work finishes.

Defer with an Effect

defer is in the context of commands and message actions. Pass it an Effect that produces the answer. It returns an Effect too, so yield it and return the result:
src/reportCommand.tsx
The SDK answers the delivery with 202 and runs the deferred Effect after the response, with the same services as the handler. When it succeeds, the SDK sends its answer with POST /v0/invocations/respond. Services the deferred Effect needs become requirements of the command, like anything else the handler yields. Inside Effect.map, TypeScript widens "public" to string, so mark it as const, or annotate the callback’s return type as InvocationAnswer from @reintersect/sdk/effect/app.

Who sees your app thinking

Until the answer arrives, Reintersect shows a row saying your app is thinking. The second argument decides who sees that row: The 202 body is always { visibility }, carrying that choice. Showing the row to everyone is opt-in because it shows which command or action ran, so use it when the answer will be public too. The answer keeps its own visibility. A private answer after a public deferral still reaches only the member who ran it, and the thinking row goes away for everyone else.

When the deferred Effect fails

If the deferred Effect fails or dies, the SDK logs the cause and answers with a private danger notice: “Couldn’t finish this. Try again.” The member sees the failure card with Run again. To answer a known failure in your own words, catch it inside the deferred Effect:
You have 15 minutes to answer, and a run takes one answer. Hosted runtimes keep deferred work alive for a limited time after the response, so hand work that can take minutes to a queue.

Answer from somewhere else

When a queue worker or another service does the work, defer without an Effect and pass the run’s interactionToken along:
src/reportCommand.tsx
defer() keeps the thinking row private; defer(undefined, { visibility: "public" }) shows it to everyone. Answer from the worker with the app client:
src/finishReport.ts
A second answer, or one after the 15 minutes, fails with ReintersectAppInteractionExpiredError.

Testing

runCommand and runMessageAction return { status: "deferred", visibility, interactionToken } for a deferred run. Yield host.settle to let the deferred Effect finish, then read the answer:
When the deferred Effect fails, the recorded answer is the SDK’s failure notice. See Testing.