Clients
The Restate SDK client library lets you invoke Restate handlers from anywhere in your application. Use this only in non-Restate services without access to the Restate Context.
Always invoke handlers via the context, if you have access to it. Restate then attaches information about the invocation to the parent invocation.
Invoking handlers with the SDK clients
Invoke a handler programmatically with the SDK clients as follows:
Add the dependency to your project
implementation("dev.restate:sdk-common:1.1.1")
Register the service you want to invoke.
Connect to Restate and invoke the handler with your preferred semantics
- Java
- Kotlin
Request-response invocations allow you to wait on a response from the handler.
Client rs = Client.connect("http://localhost:8080");String greet = GreeterServiceClient.fromClient(rs).greet("Hi");int count = GreetCounterObjectClient.fromClient(rs, "Mary").greet("Hi");
One-way invocations allow you to send a message without waiting for a response.
Client rs = Client.connect("http://localhost:8080");GreeterServiceClient.fromClient(rs).send().greet("Hi");GreetCounterObjectClient.fromClient(rs, "Mary").send().greet("Hi");
Delayed invocations allow you to schedule an invocation for a later point in time.
Client rs = Client.connect("http://localhost:8080");GreeterServiceClient.fromClient(rs).send(Duration.ofMillis(1000)).greet("Hi");GreetCounterObjectClient.fromClient(rs, "Mary").send(Duration.ofMillis(1000)).greet("Hi");
Request-response invocations allow you to wait on a response from the handler.
val rs = Client.connect("http://localhost:8080")val greet: String = GreeterServiceClient.fromClient(rs).greet("Hi")val count: Int = GreetCounterObjectClient.fromClient(rs, "Mary").greet("Hi")
One-way invocations allow you to send a message without waiting for a response.
val rs = Client.connect("http://localhost:8080")GreeterServiceClient.fromClient(rs).send().greet("Hi")GreetCounterObjectClient.fromClient(rs, "Mary").send().greet("Hi")
Delayed invocations allow you to schedule an invocation for a later point in time.
val rs = Client.connect("http://localhost:8080")GreeterServiceClient.fromClient(rs)// withClass highlight-line.send(1.seconds).greet("Hi")GreetCounterObjectClient.fromClient(rs, "Mary")// withClass highlight-line.send(1000.milliseconds).greet("Hi")
Invoke a handler idempotently
To make a service call idempotent, you can use the idempotency key feature. Add the idempotency key to the header via:
- Java
- Kotlin
Client rs = Client.connect("http://localhost:8080");GreetCounterObjectClient.fromClient(rs, "Mary").send()// withClass highlight-line.greet("Hi", CallRequestOptions.DEFAULT.withIdempotency("abcde"));
val rs = Client.connect("http://localhost:8080")GreetCounterObjectClient.fromClient(rs, "Mary").send()// withClass highlight-line.greet("Hi", CallRequestOptions.DEFAULT.withIdempotency("abcde"))
After the invocation completes, Restate persists the response for a retention period of one day (24 hours). If you re-invoke the service with the same idempotency key within 24 hours, Restate sends back the same response and doesn't re-execute the request to the service.
By using Restate and an idempotency key, you can make any service call idempotent, without any extra code or setup. This is a very powerful feature to ensure that your system stays consistent and doesn't perform the same operation multiple times.
The call options, with which we set the idempotency key, also let you add other headers to the request.
Tuning retention time
You can tune the retention time on a service-level by using the Admin API):
curl -X PATCH localhost:9070/services/MyService \-H 'content-type: application/json' \-d '{"idempotency_retention": "2days"}'
The retention time is in humantime format.
Retrieve result of invocations and workflows
You can use the client library to retrieve the results of invocations with an idempotency key or workflows. You can:
- Attach to an ongoing invocation and retrieve the result when it finishes.
- Peek at the output of a running invocation or workflow, to check if it has finished and optionally retrieve the result.
You can use the invocation ID to attach or peek at a service/object invocation that used an idempotency key:
- Java
- Kotlin
Client rs = Client.connect("http://localhost:8080");SendResponse handle =GreeterServiceClient.fromClient(rs).send().greet("Hi", CallRequestOptions.DEFAULT.withIdempotency("abcde"));// ... do something else ...// Option 1: Attach later to retrieve the resultString greeting =rs.invocationHandle(handle.getInvocationId(), JsonSerdes.STRING).attach();// Option 2: Peek to see if the result is readyOutput<String> output =rs.invocationHandle(handle.getInvocationId(), JsonSerdes.STRING).getOutput();if (output.isReady()) {String result = output.getValue();}
val rs = Client.connect("http://localhost:8080")val handle: SendResponse =GreeterServiceClient.fromClient(rs).send().greet("Hi", CallRequestOptions.DEFAULT.withIdempotency("abcde"))// ... do something else ...// Option 1: Attach later to retrieve the resultval greeting: String =rs.invocationHandle(handle.invocationId, KtSerdes.json<String>()).attach()// Option 2: Peek to see if the result is readyval output: Output<String> =rs.invocationHandle(handle.invocationId, KtSerdes.json<String>()).outputif (output.isReady) {val result = output.value}