Join the waitlist for Restate Cloud Get access
Durable execution retries on transient failures and recovers partial progress.
Embedded K/V state that commits updates atomically with durable execution progress.
Typescript, Java, and more languages coming
Built in OTel tracing for services and RPCs.
Reliable messaging, durable RPCs, transactional K/V store, durable timers, …
1. Develop a service:
npx -y @restatedev/create-app@latest && cd restate-node-template
wget https://github.com/restatedev/examples/releases/latest/download/java-hello-world-gradle.zip && unzip java-hello-world-gradle.zip -d java-hello-world-gradle && rm java-hello-world-gradle.zip && cd java-hello-world-gradle
2. Run your service:
npm install && npm run build && npm run app
./gradlew run
3. Launch Restate:
docker run --name restate_dev --rm -p 8080:8080 -p 9070:9070 -p 9071:9071 --add-host=host.docker.internal:host-gateway docker.io/restatedev/restate:latest
4. Register your service:
curl localhost:9070/deployments -H 'content-type: application/json' -d '{"uri": "http://host.docker.internal:9080"}'
5. Send a request:
curl localhost:8080/myservice/hello -H 'content-type: application/json' -d '{"request": "Restate"}'
curl localhost:8080/greeter.Greeter/Greet -H 'content-type: application/json' -d '{"name": "Restate"}'
Restate’s flexible SDKs allows you to implement a large set of useful patterns in a few lines of code.
// the request router for the target service
const callee = restate.router({
call: async (ctx: restate.RpcContext, request: { arg: string }) => {
// this will be reliably invoked via a durable event from the caller
}
});
// defines the logical location and the type signature
const calleeApi = { path: "callee" } as restate.ServiceApi<typeof callee>
// invoke from another Restate-backed service
const result = await ctx.rpc(calleeApi).call("hello " + request);
// invoke (or re-attach) with an external client
`curl http://<restate>/callee/call --json '{"request": {"arg": "..."}}' -H 'idempotency-key: <key>'`
// keyed routers enforce a single-writer for all methods of a router
// the second function parameter (the key) defines the single-writer identity
const userService = keyedRouter({
updateUser: async (ctx: RpcContext, userId: string, update: any) => {...},
moveUser: async (ctx: RpcContext, userId: string, move: any) => {...},
deleteUser: async (ctx: RpcContext, userId: string) => {...}
});
// make calls from Restate to a service idempotently across retries/suspensions
async function invoke(ctx: restate.RpcContext, request: RequestType) {
// deterministic random takes part in durable execution
const idempotencyToken = ctx.rand.uuidv4();
// side effect captures response and avoids retries after first success
await ctx.sideEffect(() => api.makeCall(request, idempotencyToken));
}
// invoke functions idempotently from external clients
`curl http://<restate>/myservice/invoke -H 'idempotency-key: <key>' --json '{"request": {...}}'`
const handleWorkflow = async (ctx: restate.RpcContext, req: Request) => {
// create a promise/future that can be completed externally
const restatePromise = await ctx.awakeable();
// pass the promise ID along with the call to external system
await ctx.sideEffect(() => clnt.doSomething(restatePromise.id))
// blocks (and suspends) until the promise is completed by external system
await restatePromise.promise;
};
// function will automatically journal actions and recover from partial
// progress to ensure all writes get applied
async function applyChange(ctx: restate.RpcContext, request: UpdateRequest) {
// write 1: Update the database. Will be automatically retried on failure.
const clientToken = ctx.rand.uuidv4();
await ctx.sideEffect(() =>
dynamodb.idempotentInsert(request.dbUpdateRecord, clientToken));
// write 2: send a message
ctx.send(messageSender).publish(request.kafkaMessage);
// write 3: set some Restate state
ctx.set("status", request);
};
const handleWorkflow = async (ctx: restate.RpcContext, req: Request) => {
// do something
// delayed background task that will execute exactly once
ctx.sendDelayed(otherService, 10_000).doSmt(req);
};
const lockService = restate.keyedRouter({
tryAcquire: async (ctx: restate.RpcContext, lockId: string) => {
const lockHolder = await ctx.get<string>(LOCK_HOLDER_STATE);
if (lockHolder !== null) {
return { acquired: false } as LockAcquisition;
}
const fencingToken = ctx.rand.uuidv4();
ctx.set(LOCK_HOLDER_STATE, fencingToken);
return { acquired: true, fencingToken } as LockAcquisition;
},
acquire: ...,
release: ...,
holdsLock: ...,
});
Restate implements low-latency durable execution with a partitioned command log.
The Restate Runtime pushes invocations to services and functions, journals the execution, and handles retries and failover. Via the journal, functions can recover partial progress after failures or actively suspend when waiting.
Restate stores long-lived k/v state for functions and pushes relevant state together with invocations.
cartService: Joe - cart=[]
addTicket ( Joe, seat2B )
reserve ( seat2B )
async addTicket = async (ctx, userId, ticketId) => {
const success = await ctx.rpc(ticketApi).reserve(ticketId);
if (success) {
const cart = await ctx.get("cart");
ctx.set("cart", cart.push(ticketId));
}
return success;
}
async reserve = async (ctx, ticketId) => {
...
}
Restate comes as a single binary that runs without any dependencies. It runs as well on your laptop as it does in the cloud.
Restate is built for modern cloud architectures and works seamlessly with services standalone, on FaaS (AWS Lambda), and as scale-out deployments on container engines like Kubernetes.
Detailed insight in execution progress and state across services
Generate OpenTelemetry traces and call trees for services, without any code or configuration.
Restate's unique way of managing inter-service communication and durable execution together means that it can generate detailed observability data right out of the box.
To the docsThe 0.8 release of Restate ships many new API improvements such as deterministic promise combinators, operation timeouts, better state management, and much more. Restate now supports patching service state in case you need to repair a service's state. Last but not least, you can deploy Restate on Kubernetes very quickly using the new Helm chart or Restate's Kubernetes operator.
Posted March 7, 2024 by Till Rohrmann and Francesco Guardiani and Giselle van Dongen and Igal Shilman and Jack Kleeman ‐ 4 min read
Part two of 'Solving durable execution’s immutability problem': How can we write code that works across time without introducing versioning problems?
Posted February 23, 2024 by Jack Kleeman ‐ 9 min read
The hardest problem in durable execution, as in many areas of infrastructure, is safe updates.
Posted February 2, 2024 by Jack Kleeman ‐ 8 min read
Restate is in beta
Try out the preview release of Restate’s managed cloud deployment:
> Get accessWant to get updates on releasesand other news?
> Subscribe