All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.restate.sdk.ContextImpl Maven / Gradle / Ivy

The newest version!
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
//
// This file is part of the Restate Java SDK,
// which is released under the MIT license.
//
// You can find a copy of the license in file LICENSE in the root
// directory of this repository or package, or at
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
package dev.restate.sdk;

import dev.restate.sdk.common.*;
import dev.restate.sdk.common.function.ThrowingSupplier;
import dev.restate.sdk.common.syscalls.Deferred;
import dev.restate.sdk.common.syscalls.EnterSideEffectSyscallCallback;
import dev.restate.sdk.common.syscalls.ExitSideEffectSyscallCallback;
import dev.restate.sdk.common.syscalls.Syscalls;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

class ContextImpl implements ObjectContext, WorkflowContext {

  final Syscalls syscalls;

  ContextImpl(Syscalls syscalls) {
    this.syscalls = syscalls;
  }

  @Override
  public String key() {
    return syscalls.objectKey();
  }

  @Override
  public Request request() {
    return syscalls.request();
  }

  @Override
  public  Optional get(StateKey key) {
    Deferred deferred = Util.blockOnSyscall(cb -> syscalls.get(key.name(), cb));

    if (!deferred.isCompleted()) {
      Util.blockOnSyscall(cb -> syscalls.resolveDeferred(deferred, cb));
    }

    return Util.unwrapOptionalReadyResult(deferred.toResult())
        .map(bs -> Util.deserializeWrappingException(syscalls, key.serde(), bs));
  }

  @Override
  public Collection stateKeys() {
    Deferred> deferred = Util.blockOnSyscall(syscalls::getKeys);

    if (!deferred.isCompleted()) {
      Util.blockOnSyscall(cb -> syscalls.resolveDeferred(deferred, cb));
    }

    return Util.unwrapResult(deferred.toResult());
  }

  @Override
  public void clear(StateKey key) {
    Util.blockOnSyscall(cb -> syscalls.clear(key.name(), cb));
  }

  @Override
  public void clearAll() {
    Util.blockOnSyscall(syscalls::clearAll);
  }

  @Override
  public  void set(StateKey key, @NonNull T value) {
    Util.blockOnSyscall(
        cb ->
            syscalls.set(
                key.name(), Util.serializeWrappingException(syscalls, key.serde(), value), cb));
  }

  @Override
  public Awaitable timer(Duration duration) {
    Deferred result = Util.blockOnSyscall(cb -> syscalls.sleep(duration, cb));
    return Awaitable.single(syscalls, result);
  }

  @Override
  public  Awaitable call(
      Target target, Serde inputSerde, Serde outputSerde, T parameter) {
    ByteBuffer input = Util.serializeWrappingException(syscalls, inputSerde, parameter);
    Deferred result = Util.blockOnSyscall(cb -> syscalls.call(target, input, cb));
    return Awaitable.single(syscalls, result)
        .map(bs -> Util.deserializeWrappingException(syscalls, outputSerde, bs));
  }

  @Override
  public  void send(Target target, Serde inputSerde, T parameter) {
    ByteBuffer input = Util.serializeWrappingException(syscalls, inputSerde, parameter);
    Util.blockOnSyscall(cb -> syscalls.send(target, input, null, cb));
  }

  @Override
  public  void send(Target target, Serde inputSerde, T parameter, Duration delay) {
    ByteBuffer input = Util.serializeWrappingException(syscalls, inputSerde, parameter);
    Util.blockOnSyscall(cb -> syscalls.send(target, input, delay, cb));
  }

  @Override
  public  T run(String name, Serde serde, ThrowingSupplier action) {
    CompletableFuture> enterFut = new CompletableFuture<>();
    syscalls.enterSideEffectBlock(
        name,
        new EnterSideEffectSyscallCallback() {
          @Override
          public void onNotExecuted() {
            enterFut.complete(new CompletableFuture<>());
          }

          @Override
          public void onSuccess(ByteBuffer result) {
            enterFut.complete(CompletableFuture.completedFuture(result));
          }

          @Override
          public void onFailure(TerminalException t) {
            enterFut.complete(CompletableFuture.failedFuture(t));
          }

          @Override
          public void onCancel(Throwable t) {
            enterFut.cancel(true);
          }
        });

    // If a failure was stored, it's simply thrown here
    CompletableFuture exitFut = Util.awaitCompletableFuture(enterFut);
    if (exitFut.isDone()) {
      // We already have a result, we don't need to execute the action
      return Util.deserializeWrappingException(
          syscalls, serde, Util.awaitCompletableFuture(exitFut));
    }

    ExitSideEffectSyscallCallback exitCallback =
        new ExitSideEffectSyscallCallback() {
          @Override
          public void onSuccess(ByteBuffer result) {
            exitFut.complete(result);
          }

          @Override
          public void onFailure(TerminalException t) {
            exitFut.completeExceptionally(t);
          }

          @Override
          public void onCancel(@Nullable Throwable t) {
            exitFut.cancel(true);
          }
        };

    T res = null;
    Throwable failure = null;
    try {
      res = action.get();
    } catch (Throwable e) {
      failure = e;
    }

    if (failure != null) {
      syscalls.exitSideEffectBlockWithException(failure, null, exitCallback);
    } else {
      syscalls.exitSideEffectBlock(
          Util.serializeWrappingException(syscalls, serde, res), exitCallback);
    }

    return Util.deserializeWrappingException(syscalls, serde, Util.awaitCompletableFuture(exitFut));
  }

  @Override
  public  Awakeable awakeable(Serde serde) throws TerminalException {
    // Retrieve the awakeable
    Map.Entry> awakeable = Util.blockOnSyscall(syscalls::awakeable);

    return new Awakeable<>(syscalls, awakeable.getValue(), serde, awakeable.getKey());
  }

  @Override
  public AwakeableHandle awakeableHandle(String id) {
    return new AwakeableHandle() {
      @Override
      public  void resolve(Serde serde, @NonNull T payload) {
        Util.blockOnSyscall(
            cb ->
                syscalls.resolveAwakeable(
                    id, Util.serializeWrappingException(syscalls, serde, payload), cb));
      }

      @Override
      public void reject(String reason) {
        Util.blockOnSyscall(cb -> syscalls.rejectAwakeable(id, reason, cb));
      }
    };
  }

  @Override
  public RestateRandom random() {
    return new RestateRandom(this.request().invocationId().toRandomSeed(), this.syscalls);
  }

  @Override
  public  DurablePromise promise(DurablePromiseKey key) {
    return new DurablePromise<>() {
      @Override
      public Awaitable awaitable() {
        Deferred result = Util.blockOnSyscall(cb -> syscalls.promise(key.name(), cb));
        return Awaitable.single(syscalls, result)
            .map(bs -> Util.deserializeWrappingException(syscalls, key.serde(), bs));
      }

      @Override
      public Output peek() {
        Deferred deferred =
            Util.blockOnSyscall(cb -> syscalls.peekPromise(key.name(), cb));

        if (!deferred.isCompleted()) {
          Util.blockOnSyscall(cb -> syscalls.resolveDeferred(deferred, cb));
        }

        return Util.unwrapOutputReadyResult(deferred.toResult())
            .map(bs -> Util.deserializeWrappingException(syscalls, key.serde(), bs));
      }
    };
  }

  @Override
  public  DurablePromiseHandle promiseHandle(DurablePromiseKey key) {
    return new DurablePromiseHandle<>() {
      @Override
      public void resolve(T payload) throws IllegalStateException {
        Deferred deferred =
            Util.blockOnSyscall(
                cb ->
                    syscalls.resolvePromise(
                        key.name(),
                        Util.serializeWrappingException(syscalls, key.serde(), payload),
                        cb));

        if (!deferred.isCompleted()) {
          Util.blockOnSyscall(cb -> syscalls.resolveDeferred(deferred, cb));
        }

        Util.unwrapResult(deferred.toResult());
      }

      @Override
      public void reject(String reason) throws IllegalStateException {
        Deferred deferred =
            Util.blockOnSyscall(cb -> syscalls.rejectPromise(key.name(), reason, cb));

        if (!deferred.isCompleted()) {
          Util.blockOnSyscall(cb -> syscalls.resolveDeferred(deferred, cb));
        }

        Util.unwrapResult(deferred.toResult());
      }
    };
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy