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.

Create an account at platform.respan.ai and grab an API key.

Run npx @respan/cli setup to set up with your coding agent.

Setup

1

Install packages

$pip install respan-ai respan-instrumentation-restate restate-sdk hypercorn
2

Set your API key

$export RESPAN_API_KEY="YOUR_RESPAN_API_KEY"
3

Initialize and register handlers

Initialize Respan before decorating Restate handlers. The instrumentor adds its invocation context manager when handlers are registered.

Python
1import asyncio
2
3import hypercorn
4import hypercorn.asyncio
5import restate
6from respan import Respan
7from respan_instrumentation_restate import RestateInstrumentor
8
9respan = Respan(
10 instrumentations=[RestateInstrumentor()],
11)
12
13greeter = restate.Service("Greeter")
14
15
16@greeter.handler()
17async def greet(ctx: restate.Context, name: str) -> str:
18 return f"Hello, {name}!"
19
20
21app = restate.app(services=[greeter])
22
23config = hypercorn.Config()
24config.bind = ["0.0.0.0:9080"]
25
26try:
27 asyncio.run(hypercorn.asyncio.serve(app, config))
28finally:
29 respan.shutdown()
4

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.

5

View your trace

Open the Traces page to inspect each invocation’s handler and durable-execution context.

What gets traced

Restate handlerRespan spanCaptured Restate context
Service.handler()taskService and handler names, invocation ID, replay state
VirtualObject.handler()taskObject key, exclusive/shared kind, invocation ID, replay state
Workflow.main()workflowWorkflow key, invocation ID, replay state
Workflow.handler()taskWorkflow 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:

1respan = Respan(
2 instrumentations=[RestateInstrumentor(capture_content=False)]
3)

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.