Restate Skill
Product Summary
Restate is a lightweight runtime that turns AI agents, workflows, and backend services into durable processes. It sits in front of your services (similar to a reverse proxy) and automatically handles resilience, state management, and reliable communication.
Key files and concepts:
- Services are defined using the Restate SDK (TypeScript, Java, Kotlin, Python, Go, Rust, Ruby)
- Handlers are durable functions that execute with automatic failure recovery
- Invocations are requests to execute handlers, tracked through completion
- Durable execution journals every step, replaying completed steps on retry
- Virtual Objects provide stateful, key-addressable services with persistent K/V state
- Workflows are long-lived processes with defined lifecycle and external event handling
Primary entry points:
- Restate Server:
restate-server binary (Rust-based, single binary deployment)
- Restate CLI:
restate command for deployment, service management, and invocation control
- Admin API: REST API at port 9070 for deployment and service management
- HTTP Ingress: Port 8080 for invoking services
- UI: Port 9070 for visual service management and debugging
SDKs: TypeScript (@restatedev/restate-sdk), Java/Kotlin, Python, Go, Rust, Ruby
When to Use
Reach for Restate when:
- Building services that need automatic failure recovery without manual retry logic
- Implementing AI agents that must survive crashes and resume from exact checkpoint
- Creating workflows with multiple steps that need to preserve progress across failures
- Coordinating calls across microservices with guaranteed exactly-once execution
- Processing events with durable, transactional semantics
- Running long-lived operations on serverless platforms (Lambda, Cloud Run) without paying for wait time
- Needing persistent state tied to specific entities (user sessions, chat conversations, orders)
- Implementing human-in-the-loop workflows that pause and resume on external signals
Do not use Restate for:
- Simple stateless request-response services (use a standard web framework)
- Real-time streaming that requires sub-millisecond latency
- Services that don't need failure recovery or state persistence
Quick Reference
Service Types
| Type |
Use Case |
State |
Concurrency |
| Basic Service |
Stateless handlers, utility functions |
None |
Unlimited concurrent |
| Virtual Object |
Stateful entities (users, carts, sessions) |
K/V store per key |
Single writer per key, concurrent readers |
| Workflow |
Long-running multi-step processes |
K/V store per workflow ID |
Run handler once, shared handlers concurrent |
Invocation Methods
# Synchronous call (wait for response)
curl localhost:8080/restate/call/MyService/myHandler --json '{"key": "value"}'
# Asynchronous send (fire and forget)
curl localhost:8080/restate/send/MyService/myHandler --json '{"key": "value"}'
# Delayed message
curl "localhost:8080/restate/send/MyService/myHandler?delay=10s" --json '{"key": "value"}'
# With idempotency key
curl localhost:8080/restate/call/MyService/myHandler \
-H 'idempotency-key: unique-key-123' \
--json '{"key": "value"}'
# Virtual Object handler
curl localhost:8080/restate/call/MyObject/objectKey/myHandler --json '{"key": "value"}'
# Workflow
curl localhost:8080/restate/call/MyWorkflow/workflowId/run --json '{"key": "value"}'
CLI Commands
# Start Restate server
restate-server
# Register a service deployment
restate deployments register http://localhost:9080
# List registered services
restate services list
# Invoke a handler
restate invocations invoke MyService myHandler '{"name": "Alice"}'
# Cancel an invocation
restate invocations cancel <invocation-id>
# Kill an invocation
restate invocations kill <invocation-id>
# Resume a paused invocation
restate invocations resume <invocation-id>
# Edit service configuration
restate services config edit MyService
# View Restate version
restate version
Durable Execution Patterns
// Wrap non-deterministic operations
await ctx.run("operation-name", async () => {
return await externalAPI.call();
});
// Sleep/timers
await ctx.sleep({ seconds: 5 });
// State access (Virtual Objects/Workflows)
await ctx.set("key", value);
const value = await ctx.get("key");
// Service-to-service calls
const result = await ctx.serviceClient(MyService).myHandler(input);
// Awakeables (wait for external events)
const { id, promise } = ctx.awakeable();
// Later: resolve from another handler
await ctx.resolveAwakeable(id, result);
Configuration Levels (highest to lowest priority)
- Handler-level options (in SDK code)
- Service-level options (in SDK code)
- CLI/UI overrides (temporary, until next deployment)
- Restate server config file
- Environment variables
- Built-in defaults
Decision Guidance
When to Use Virtual Objects vs. Workflows
| Aspect |
Virtual Object |
Workflow |
| Lifecycle |
Indefinite, shared handlers always callable |
Single run, then read-only shared handlers |
| State |
Persistent indefinitely |
Cleared after retention period |
| Use case |
User sessions, shopping carts, chat state |
Approval processes, multi-step operations |
| Concurrency |
Single writer per key, concurrent readers |
Run handler exclusive, shared handlers concurrent |
| Scaling |
Horizontal (many keys) |
Horizontal (many workflow IDs) |
When to Use Idempotency Keys vs. Retries
| Scenario |
Approach |
| Duplicate client requests |
Use idempotency key header; Restate deduplicates automatically |
| Transient failures (network, timeout) |
Restate retries automatically with exponential backoff |
| Long-running operations |
Increase inactivity/abort timeouts; use durable steps |
| Rate-limited APIs |
Use RetryableError with custom delay from Retry-After header |
Error Handling: Terminal vs. Transient
| Error Type |
Behavior |
Example |
| Transient (default) |
Retried with exponential backoff |
Network timeout, service unavailable |
| Terminal |
Not retried, propagated immediately |
Invalid input, business rule violation |
| RetryableError |
Retried after custom delay |
Rate limit with Retry-After header |
Workflow
Typical Task: Build and Deploy a Durable Service
- Define the service in your SDK (TypeScript/Java/Python/Go)
- Create handlers using restate.service(), restate.object(), or restate.workflow() - Wrap external calls in ctx.run() for durability - Use ctx.set()/ctx.get() for state (Virtual Objects/Workflows only)
- Run the service locally
- Start Restate server: restate-server - Start your service: npm run dev or equivalent - Service listens on port 9080 by default
- Register the deployment
- CLI: restate deployments register http://localhost:9080 - Or use UI at localhost:9070 - Restate discovers handlers via HTTP introspection
- Invoke handlers
- HTTP: curl localhost:8080/restate/call/ServiceName/handlerName - CLI: restate invocations invoke ServiceName handlerName - SDK clients: ctx.serviceClient(MyService).myHandler(input)
- Monitor and debug
- UI at localhost:9070 shows execution traces, state, and invocation status - CLI: restate invocations list, restate invocations describe <id> - Logs show journal entries and step-by-step execution
- Deploy to production
- Deploy service to your infrastructure (Kubernetes, Lambda, Cloud Run, etc.) - Register deployment with Restate: restate deployments register <production-url> - Restate Cloud or self-hosted Restate server handles orchestration
Typical Task: Handle Failures and Retries
- Understand the error
- Check if it's transient (network, timeout) or terminal (invalid input) - View error in UI or CLI: restate invocations describe <id>
- Configure retry policy (if transient)
- At handler level: set retryPolicy in handler options - At service level: set retryPolicy in service options - At run-block level: pass RetryPolicy to ctx.run()
- Throw terminal errors (if not retryable)
- Use throw new TerminalError("message") in TypeScript - Use raise TerminalError("message") in Python - Terminal errors stop retries and propagate to caller
- Implement compensation (if needed)
- Catch terminal errors in try-catch - Undo previous actions (sagas pattern) - Propagate error or send to dead-letter queue
- Resume paused invocations
- CLI: restate invocations resume <id> - UI: Click resume on paused invocation - Invocation retries from last checkpoint
Common Gotchas
- Non-deterministic operations outside
ctx.run(): Random numbers, timestamps, or external calls outside ctx.run() will be replayed differently on retry, breaking determinism. Always wrap in ctx.run().
- Modifying state without
ctx.set(): Changes to local variables won't persist across retries. Use ctx.set() for Virtual Objects/Workflows.
- Forgetting to register deployments: Services won't be discoverable until registered. Always run
restate deployments register after deploying.
- Timeout too short for long operations: LLM calls, database queries, or external APIs may exceed default 1-minute inactivity timeout. Increase
inactivityTimeout and abortTimeout in service config.
- Idempotency key retention too short: Default is 24 hours. If clients retry after 24 hours, they'll get a new invocation instead of the cached result. Increase
idempotencyRetention for longer windows.
- Workflow run handler called twice: Workflows only accept the run handler once per workflow ID. Resubmission fails with "Previously accepted". Use the invocation ID from
x-restate-id header to attach to existing workflow.
- State not cleared after workflow completion: Workflow state persists for the retention period (default 24 hours). After that, shared handlers can't access state. Plan accordingly.
- Mixing eager and lazy state: Eager state loads all K/V entries upfront; lazy loads on-demand. Choose one strategy per service to avoid confusion.
- Forgetting to handle cancellations: When invocations are cancelled, they throw a terminal error at the next
await. Implement compensation logic to clean up.
- Retrying forever without bounds: Default retry policy retries indefinitely. Set
maxAttempts or maxDuration to prevent infinite retries on bugs.
Verification Checklist
Before submitting work with Restate:
Resources
Comprehensive navigation: https://docs.restate.dev/llms.txt
Critical documentation:
For additional documentation and navigation, see: https://docs.restate.dev/llms.txt