Restate (tracing)
Restate is a durable execution system with Python Service, Virtual Object, and Workflow handlers. Respan uses Restate’s invocation_context_managers extension point to create one span around each handler invocation attempt.
Set up Respan
Create an account at platform.respan.ai and grab an API key .
Example project
Paste this into your coding agent:
Help me set up Respan tracing with the Restate integration.
Follow https://www.respan.ai/docs/integrations/restate.mdSetup
Install packages
pip install respan-ai respan-instrumentation-restate restate-sdk hypercornSet your API key
export RESPAN_API_KEY="YOUR_RESPAN_API_KEY"Initialize and register handlers
Initialize Respan before decorating Restate handlers. The instrumentor adds its invocation context manager when handlers are registered.
import asyncio
import hypercorn
import hypercorn.asyncio
import restate
from respan import Respan
from respan_instrumentation_restate import RestateInstrumentor
respan = Respan(
instrumentations=[RestateInstrumentor()],
)
greeter = restate.Service("Greeter")
@greeter.handler()
async def greet(ctx: restate.Context, name: str) -> str:
return f"Hello, {name}!"
app = restate.app(services=[greeter])
config = hypercorn.Config()
config.bind = ["0.0.0.0:9080"]
try:
asyncio.run(hypercorn.asyncio.serve(app, config))
finally:
respan.shutdown()Run Restate
Start a local Restate server, register the Python endpoint, and invoke the handler:
# Terminal 1
npx -y @restatedev/restate-server
# Terminal 2
python app.py
# Terminal 3
npx -y @restatedev/restate deployments register --force --yes http://localhost:9080
curl -X POST http://localhost:8080/Greeter/greet \
-H "content-type: application/json" \
-d '"Ada"'You can also use the official Restate server and CLI binaries from Restate releases if the npm launcher does not provide a binary for your platform.
View your trace
Open the Traces page to inspect each invocation’s handler and durable-execution context.
What gets traced
| Restate handler | Respan span | Captured Restate context |
|---|---|---|
Service.handler() | task | Service and handler names, invocation ID, replay state |
VirtualObject.handler() | task | Object key, exclusive/shared kind, invocation ID, replay state |
Workflow.main() | workflow | Workflow key, invocation ID, replay state |
Workflow.handler() | task | Workflow key, shared-handler context, invocation ID, replay state |
When Restate provides them, the adapter also records scope, limit key, idempotency key, service metadata, and handler metadata. The request is deserialized through the handler’s configured Restate serde.
Restate invocation IDs are mapped to Respan trace groups. Virtual Object and Workflow keys are mapped to thread identifiers.
Handler results
Restate’s invocation context managers surround execution but do not receive the handler’s serialized return value. Successful spans therefore record a completion status, not an invented response body. Failed spans record the real exception class, message, and status code exposed by Restate, including custom TerminalError codes.
This behavior intentionally differs from integrations whose native hooks expose a return value.
Replay and content controls
The adapter records whether Restate reports the invocation as replaying; it traces the actual invocation attempt exposed to the context manager.
Disable deserialized request capture when request bodies may contain sensitive data:
respan = Respan(
instrumentations=[RestateInstrumentor(capture_content=False)]
)Service, handler, invocation, replay, key, scope, idempotency, and status fields remain available.
Lifecycle
The instrumentor patches handler registration on Service, VirtualObject, and Workflow. Handlers registered before activation are not retrofitted. Each service object receives at most one Respan context manager, and existing user-provided context managers are preserved.
activate() and deactivate() are reference-counted. Call respan.shutdown() during service shutdown to flush pending spans and restore the registration methods.