Documentation / Advanced
Dispatch async work safely
Persist the operation before dispatch. Keep its identity stable through uncertain outcomes and ownership changes.
Declare the async contract
The callback is required and authenticated. Retry generations get separate credentials. Fixed, linear and exponential backoff are supported policy values. Adapter kinds describe contracts; customer/provider integration still has to be configured.
Recovery can preserve the callback credential’s original issued epoch. Current-owner fencing is a separate check; always return the issued credential unchanged.
{
"type": "async_tool",
"timeout": "30m",
"callback": {
"required": true,
"authenticated": true
},
"retry": {
"maxAttempts": 3,
"backoff": "exponential",
"initialInterval": "5s",
"maxInterval": "1m"
}
}Complete example · JSON / YAML
JSON
{
"name": "advanced-async",
"version": "1.0.0",
"controls": {
"policyVersion": 1,
"budgets": [
{
"id": "research",
"resource": "model_cost",
"unit": "usd",
"limit": "5.00",
"enforcement": "hard",
"maxExposurePerOp": "0.50",
"scope": "workflow_run",
"reset": "operator_amendment_only",
"violation": "pause"
}
]
},
"phases": [
{
"id": "research",
"type": "async_tool",
"tool": "example-provider",
"timeout": "30m",
"callback": {
"required": true,
"authenticated": true
},
"retry": {
"maxAttempts": 3,
"backoff": "exponential",
"initialInterval": "5s",
"maxInterval": "1m"
},
"adapter": {
"kind": "external_https",
"target": "https://provider.example/jobs",
"idempotentDispatch": true,
"supportsStatusLookup": true,
"supportsRemoteCancel": true
},
"controls": {
"budget": "research"
},
"terminal": true
}
]
}YAML
name: advanced-async
version: 1.0.0
controls:
policyVersion: 1
budgets:
- id: research
resource: model_cost
unit: usd
limit: "5.00"
enforcement: hard
maxExposurePerOp: "0.50"
scope: workflow_run
reset: operator_amendment_only
violation: pause
phases:
- id: research
type: async_tool
tool: example-provider
timeout: 30m
callback:
required: true
authenticated: true
retry:
maxAttempts: 3
backoff: exponential
initialInterval: 5s
maxInterval: 1m
adapter:
kind: external_https
target: https://provider.example/jobs
idempotentDispatch: true
supportsStatusLookup: true
supportsRemoteCancel: true
controls:
budget: research
terminal: truerippflow controls validate advanced-async.workflow.yaml --jsonExpected: ok: true. This checks the contract; deployment/enforcement is separate.
Build the callback with the SDK
Use the issued request helper to preserve operation, generation and credential binding. This builds a payload; send it only through the installation’s issued callback transport. Do not log its bearer credential.
use rippflow_sdk::{AsyncCallbackPayload, AsyncToolRequest};
use serde_json::json;
pub fn complete_example(req: &AsyncToolRequest) -> AsyncCallbackPayload {
req.complete(json!({"summary": "Example result"}))
}Recover uncertain dispatch
Reuse the issued side-effect idempotency key. Use provider status lookup when available; an uncertain non-idempotent dispatch must not be blindly repeated. Cancellation revokes wait intent/credentials; a remote cancel capability is separate. Late callbacks are audited and must not revive cancelled work.
Track external-operation concurrency and budget reservations separately from the released worker slot.
Checkpoint context, reference large artifacts
DurableAgentContext binds context version, checkpoint sequence, ownership epoch, budget summaries, approval gates and artifact references. Use conditional version updates. Inline state defaults to 4 KiB; larger content uses offload references with plaintext/envelope digests and retention.
Inspect through research examples and execution history. Keep callback credentials and sensitive artifact content out of logs.
rippflow executions inspect EXECUTION_ID --json
rippflow executions history EXECUTION_ID --jsonVerified sources
Checked 2026-11-05.
- async_execution.rs 04cb082 · main
- Async callback SDK 7f5ea32 · main
