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

akka.projection.javadsl.StatefulHandler.scala Maven / Gradle / Ivy

There is a newer version: 1.5.0-M4
Show newest version
/*
 * Copyright (C) 2020-2023 Lightbend Inc. 
 */

package akka.projection.javadsl

import java.util.concurrent.CompletionStage

import akka.Done

abstract class StatefulHandler[State, Envelope] extends Handler[Envelope] {

  private var state: CompletionStage[State] = _

  /**
   * Invoked to load the initial state when the projection is started or if previous `process` failed.
   */
  def initialState(): CompletionStage[State]

  /**
   * The `process` method is invoked for each `Envelope`.
   * One envelope is processed at a time. The returned `CompletionStage` is to be completed when the processing
   * of the `envelope` has finished. It will not be invoked with the next envelope until after the returned
   * `CompletionStage` has been completed.
   *
   * The `state` is the completed value of the previously returned `CompletionStage` or the `initialState`.
   * If the previously returned `CompletionStage` failed it will call `initialState`
   * again and use that value.
   */
  @throws(classOf[Exception])
  def process(state: State, envelope: Envelope): CompletionStage[State]

  /**
   * Calls [[StatefulHandler.initialState]] when the projection is started.
   */
  final override def start(): CompletionStage[Done] = {
    state = initialState()
    state.thenApply(_ => Done)
  }

  /**
   * Calls `process(state, envelope)` with the completed value of the previously returned `CompletionStage`
   * or the `initialState`. If the previously returned `CompletionStage` failed it will call `initialState`
   * again and use that value.
   */
  final override def process(envelope: Envelope): CompletionStage[Done] = {
    val stateCompletableFuture = state.toCompletableFuture
    val newState =
      if (stateCompletableFuture.isDone)
        state
      else if (stateCompletableFuture.isCompletedExceptionally)
        initialState()
      else
        throw new IllegalStateException(
          "Process called before previous CompletionStage completed. " +
          "Did you share the same handler instance between several Projection instances? " +
          "Otherwise, please report issue at " +
          "https://github.com/akka/akka-projection/issues")

    state = newState.thenCompose(s => process(s, envelope))
    state.thenApply(_ => Done)
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy