Callbacks
Callbacks let a downstream node send data back to an upstream service that is still running. This enables bidirectional communication within a task — a service can pause, wait for a response from a later node, and then continue based on that response.
When To Use Them
Section titled “When To Use Them”Callbacks are useful when a service needs input from a downstream node before it can proceed:
- A service generates options → a logic node selects one → the service continues with the selection
- A service requests approval → a downstream step decides → the service acts on the decision
- A service emits partial data → a logic node enriches it → the service incorporates the result
How It Works
Section titled “How It Works”1. The Service Creates and Yields a Callback
Section titled “1. The Service Creates and Yields a Callback”import { createService, createCallback } from '@requence/service'
createService('1.0.0', async function* (ctx) { const callback = createCallback<number>()
// Yield the callback as part of the output yield { chooseAmount: callback }
// Wait for the downstream node to respond const amount = await callback.response()
// Continue with the received value yield ctx.toOutput('result', { total: amount * 10 })})from requence.service import Servicefrom requence.requence_callback import Callback
def handler(ctx): callback = Callback()
# Yield the callback as part of the output yield {"chooseAmount": callback}
# Wait for the downstream node to respond amount = callback.response()
# Continue with the received value yield ctx.to_output("result", {"total": amount * 10})
Service("1.0.0", handler)2. A Downstream Node Invokes the Callback
Section titled “2. A Downstream Node Invokes the Callback”The callback arrives as a callable function on the downstream node’s input. Calling it sends the value back to the waiting service:
// Logic node scriptcontext.input.chooseAmount(42)3. The Service Receives the Response
Section titled “3. The Service Receives the Response”After the downstream node invokes the callback, callback.response() resolves with the value (42 in this example). The service can then continue its execution and yield further results.
Example
Section titled “Example”A complete task template using callbacks might look like this:
- Entry → Service (generator, yields a callback) → Logic (invokes callback) → Exit
- The service also has a named output
resultthat connects directly to the exit
// Service handlercreateService('1.0.0', async function* (ctx) { const callback = createCallback<number>() yield { multiply: callback }
const factor = await callback.response() yield ctx.toOutput('done', { result: factor * 100 })})// Logic node scriptcontext.input.multiply(10)The task completes with { result: 1000 }.
Multiple Callbacks
Section titled “Multiple Callbacks”A service can create and yield multiple callbacks, either sequentially or in the same yield:
createService('1.0.0', async function* (ctx) { const approve = createCallback<boolean>() const setAmount = createCallback<number>()
yield { approve, setAmount }
const [approved, amount] = await Promise.all([ approve.response(), setAmount.response(), ])
if (approved) { yield ctx.toOutput('confirmed', { amount }) }})createCallback is also available as a global inside logic nodes — see Logic Nodes.