Interface Context

All Known Subinterfaces:
ObjectContext, SharedObjectContext, SharedWorkflowContext, WorkflowContext

public interface Context
This interface exposes the Restate functionalities to Restate services. It can be used to interact with other Restate services, record non-deterministic closures, execute timers and synchronize with external systems.

Error handling

All methods of this interface, and related interfaces, throws either TerminalException or AbortedExecutionException, where the former can be caught and acted upon, while the latter MUST NOT be caught, but simply propagated for clean up purposes.

Serialization and Deserialization

The methods of this interface that need to serialize or deserialize payloads have an overload both accepting Class or TypeTag. Depending on your case, you might use the Class overload for simple types, and TypeRef for generic types:

 String result = ctx.run(
    "my-http-request",
    String.class,
    () -> doHttpRequest().getResult()
 ).await();

 List<String> result = ctx.run(
    "my-http-request",
    new TypeRef<>(){ },
    () -> doHttpRequest().getResult()
 ).await();
 
By default, Jackson Databind will be used for all serialization/deserialization. Check SerdeFactory for more details on how to customize that.

Thread safety

This interface MUST NOT be accessed concurrently since it can lead to different orderings of user actions, corrupting the execution of the invocation.
  • Method Details

    • request

      dev.restate.sdk.common.HandlerRequest request()
    • call

      <T, R> CallDurableFuture<R> call(dev.restate.common.Request<T,R> request)
      Invoke another Restate service method.
      Parameters:
      request - Request object. For each service, a class called <your_class_name>Handlers is generated containing the request builders.
      Returns:
      an DurableFuture that wraps the Restate service method result.
    • send

      default <T, R> InvocationHandle<R> send(dev.restate.common.Request<T,R> request)
      Invoke another Restate service without waiting for the response.
      Parameters:
      request - Request object. For each service, a class called <your_class_name>Handlers is generated containing the request builders.
      Returns:
      an InvocationHandle that can be used to retrieve the invocation id, cancel the invocation, attach to its result.
    • send

      <T, R> InvocationHandle<R> send(dev.restate.common.Request<T,R> request, Duration delay)
      Invoke another Restate service without waiting for the response.
      Parameters:
      request - Request object. For each service, a class called <your_class_name>Handlers is generated containing the request builders.
      delay - the delay to send the request
      Returns:
      an InvocationHandle that can be used to retrieve the invocation id, cancel the invocation, attach to its result.
    • invocationHandle

      <R> InvocationHandle<R> invocationHandle(String invocationId, dev.restate.serde.TypeTag<R> responseTypeTag)
    • invocationHandle

      default <R> InvocationHandle<R> invocationHandle(String invocationId, Class<R> responseClazz)
      Get an InvocationHandle for an already existing invocation. This will let you interact with a running invocation, for example to cancel it or retrieve its result.
      Parameters:
      invocationId - The invocation to interact with.
      responseClazz - The response class.
    • invocationHandle

      default InvocationHandle<dev.restate.common.Slice> invocationHandle(String invocationId)
      Like invocationHandle(String, Class), without providing a response parser
    • sleep

      default void sleep(Duration duration)
      Causes the current execution of the function invocation to sleep for the given duration.
      Parameters:
      duration - for which to sleep.
    • timer

      default DurableFuture<Void> timer(Duration duration)
      Causes the start of a timer for the given duration. You can await on the timer end by invoking DurableFuture.await().
      Parameters:
      duration - for which to sleep.
    • timer

      DurableFuture<Void> timer(String name, Duration duration)
      Causes the start of a timer for the given duration. You can await on the timer end by invoking DurableFuture.await().
      Parameters:
      name - name used for observability
      duration - for which to sleep.
    • run

      default <T> T run(String name, Class<T> clazz, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Execute a closure, recording the result value in the journal. The result value will be re-played in case of re-invocation (e.g. because of failure recovery or suspension point) without re-executing the closure.
      
       String result = ctx.run(
          "my-http-request",
          String.class,
          () -> doHttpRequest().getResult()
       ).await();
       
      If the result type contains generic types, e.g. a List<String>, you should use run(String, TypeTag, ThrowingSupplier). See Context for more details about serialization and deserialization.

      You can name this closure using the name parameter. This name will be available in the observability tools.

      The closure should tolerate retries, that is Restate might re-execute the closure multiple times until it records a result. You can control and limit the amount of retries using run(String, Class, RetryPolicy, ThrowingSupplier).

      Error handling: Errors occurring within this closure won't be propagated to the caller, unless they are TerminalException. Consider the following code:

      
       // Bad usage of try-catch outside the run
       try {
           ctx.run(() -> {
               throw new IllegalStateException();
           }).await();
       } catch (IllegalStateException e) {
           // This will never be executed,
           // but the error will be retried by Restate,
           // following the invocation retry policy.
       }
      
       // Good usage of try-catch outside the run
       try {
           ctx.run(() -> {
               throw new TerminalException("my error");
           }).await();
       } catch (TerminalException e) {
           // This is invoked
       }
       
      To propagate run failures to the call-site, make sure to wrap them in TerminalException.
      Type Parameters:
      T - type of the return value.
      Parameters:
      name - name of the side effect.
      clazz - the class of the return value, used to serialize/deserialize it.
      action - closure to execute.
      Returns:
      value of the run operation.
      Throws:
      dev.restate.sdk.common.TerminalException
    • run

      default <T> T run(String name, dev.restate.serde.TypeTag<T> typeTag, dev.restate.sdk.common.RetryPolicy retryPolicy, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Like run(String, TypeTag, ThrowingSupplier), but using a custom retry policy.

      When a retry policy is not specified, the run will be retried using the Restate invoker retry policy, which by default retries indefinitely.

      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • run

      default <T> T run(String name, Class<T> clazz, dev.restate.sdk.common.RetryPolicy retryPolicy, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Like run(String, Class, ThrowingSupplier), but using a custom retry policy.

      When a retry policy is not specified, the run will be retried using the Restate invoker retry policy, which by default retries indefinitely.

      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • run

      default <T> T run(String name, dev.restate.serde.TypeTag<T> typeTag, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Like run(String, Class, ThrowingSupplier), but providing a TypeTag.

      See Context for more details about serialization and deserialization.

      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • run

      default <T> T run(dev.restate.serde.TypeTag<T> typeTag, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • run

      default <T> T run(Class<T> clazz, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • run

      default void run(String name, dev.restate.sdk.common.RetryPolicy retryPolicy, dev.restate.common.function.ThrowingRunnable runnable) throws dev.restate.sdk.common.TerminalException
      Like run(String, ThrowingRunnable), but without a return value and using a custom retry policy.

      When a retry policy is not specified, the run will be retried using the Restate invoker retry policy, which by default retries indefinitely.

      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • run

      default void run(String name, dev.restate.common.function.ThrowingRunnable runnable) throws dev.restate.sdk.common.TerminalException
      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • run

      default void run(dev.restate.common.function.ThrowingRunnable runnable) throws dev.restate.sdk.common.TerminalException
      Like run(Class, ThrowingSupplier) without output.
      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • runAsync

      default <T> DurableFuture<T> runAsync(String name, Class<T> clazz, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Execute a closure asynchronously. This is like run(String, Class, ThrowingSupplier), but it returns a DurableFuture that you can combine and select.
      
       // Fan-out
       var resultFutures = subTasks.stream()
               .map(task ->
                  ctx.runAsync(
                       task.description(),
                       String.class,
                       () -> task.execute()
                  )
               )
               .toList();
      
       // Await all of them
       DurableFuture.all(resultFutures).await();
      
       // Fan in - Aggregate the results
       var results = resultFutures.stream()
               .map(future -> future.await())
               .toList();
       
      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • runAsync

      default <T> DurableFuture<T> runAsync(String name, dev.restate.serde.TypeTag<T> typeTag, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Like runAsync(String, Class, ThrowingSupplier), but providing a TypeTag.

      See Context for more details about serialization and deserialization.

      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • runAsync

      default <T> DurableFuture<T> runAsync(String name, Class<T> clazz, dev.restate.sdk.common.RetryPolicy retryPolicy, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Like runAsync(String, Class, ThrowingSupplier), but using a custom retry policy.

      When a retry policy is not specified, the run will be retried using the Restate invoker retry policy, which by default retries indefinitely.

      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • runAsync

      <T> DurableFuture<T> runAsync(String name, dev.restate.serde.TypeTag<T> typeTag, dev.restate.sdk.common.RetryPolicy retryPolicy, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Like runAsync(String, TypeTag, ThrowingSupplier), but using a custom retry policy.

      When a retry policy is not specified, the run will be retried using the Restate invoker retry policy, which by default retries indefinitely.

      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • runAsync

      default <T> DurableFuture<T> runAsync(dev.restate.serde.TypeTag<T> typeTag, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • runAsync

      default <T> DurableFuture<T> runAsync(Class<T> clazz, dev.restate.common.function.ThrowingSupplier<T> action) throws dev.restate.sdk.common.TerminalException
      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • runAsync

      default DurableFuture<Void> runAsync(String name, dev.restate.sdk.common.RetryPolicy retryPolicy, dev.restate.common.function.ThrowingRunnable runnable) throws dev.restate.sdk.common.TerminalException
      Like runAsync(String, Class, ThrowingSupplier), but without an output and using a custom retry policy.

      When a retry policy is not specified, the run will be retried using the Restate invoker retry policy, which by default retries indefinitely.

      Throws:
      dev.restate.sdk.common.TerminalException
      See Also:
    • runAsync

      default DurableFuture<Void> runAsync(String name, dev.restate.common.function.ThrowingRunnable runnable) throws dev.restate.sdk.common.TerminalException
      Throws:
      dev.restate.sdk.common.TerminalException
    • runAsync

      default DurableFuture<Void> runAsync(dev.restate.common.function.ThrowingRunnable runnable) throws dev.restate.sdk.common.TerminalException
      Throws:
      dev.restate.sdk.common.TerminalException
    • awakeable

      default <T> Awakeable<T> awakeable(Class<T> clazz)
      Create an Awakeable, addressable through Awakeable.id().

      You can use this feature to implement external asynchronous systems interactions, for example you can send a Kafka record including the Awakeable.id(), and then let another service consume from Kafka the responses of given external system interaction by using awakeableHandle(String).

      Parameters:
      clazz - the response type to use for deserializing the Awakeable result. When using generic types, use awakeable(TypeTag) instead.
      Returns:
      the Awakeable to await on.
      See Also:
    • awakeable

      <T> Awakeable<T> awakeable(dev.restate.serde.TypeTag<T> typeTag)
      Create an Awakeable, addressable through Awakeable.id().

      You can use this feature to implement external asynchronous systems interactions, for example you can send a Kafka record including the Awakeable.id(), and then let another service consume from Kafka the responses of given external system interaction by using awakeableHandle(String).

      Parameters:
      typeTag - the response type tag to use for deserializing the Awakeable result.
      Returns:
      the Awakeable to await on.
      See Also:
    • awakeableHandle

      AwakeableHandle awakeableHandle(String id)
      Create a new AwakeableHandle for the provided identifier. You can use it to AwakeableHandle.resolve(TypeTag, Object) or AwakeableHandle.reject(String) the linked Awakeable.
      See Also:
    • random

      RestateRandom random()
      Returns a deterministic random.
      See Also: