Skip to content

Fire events and inquiry

This section describes how to fire sensory events into a Baker process, and how to query information from a running Baker process.

Note

For the Java API most methods return a CompletableFuture<A>, in the Scala API they return Future<A>. The Kotlin API makes use of suspending functions, and thus does not wrap the return type. To keep things readable, the descriptions in this section reason from Java's perspective.

Fire sensory events

To trigger a Baker process you'll need to fire a sensory event. After firing an event, you may want to continue your asynchronous computation at one of the following moments:

  1. Right after the event was received, but before any interactions are executed.
  2. After all interactions have completed. At this point the process is either finished, or requires other sensory events to continue.
  3. As soon one of the interactions fires a specific event.

To this end, the Baker interface exposes one method to fire an event and 2 methods to wait. We'll discuss each of those in more detail.

Fire sensory event and wait for acknowledgement of it's reception.

This method completes right after the event was received, but before any interactions are executed.

package examples.java.application;

import com.ing.baker.runtime.javadsl.Baker;
import com.ing.baker.runtime.javadsl.EventInstance;
import examples.java.events.OrderPlaced;

public class FireSensoryEventAndAwaitReceived {

    private final Baker baker;

    public FireSensoryEventAndAwaitReceived(Baker baker) {
        this.baker = baker;
    }

    public void example(String recipeInstanceId, OrderPlaced orderPlaced) {
        var eventInstance = EventInstance.from(orderPlaced);
        var sensoryEventStatus = baker.fireSensoryEventAndAwaitReceived(recipeInstanceId, eventInstance).join();
    }
}
package examples.kotlin.application

import com.ing.baker.runtime.javadsl.EventInstance
import com.ing.baker.runtime.kotlindsl.Baker
import examples.kotlin.events.OrderPlaced

class FireSensoryEventAndAwaitReceived(private val baker: Baker) {

    suspend fun example(recipeInstanceId: String, orderPlaced: OrderPlaced) {
        val orderPlacedEvent = EventInstance.from(orderPlaced)
        val sensoryEventStatus = baker.fireSensoryEventAndAwaitReceived(recipeInstanceId, orderPlacedEvent)
    }
}
package examples.scala.application

import com.ing.baker.runtime.scaladsl.{Baker, EventInstance}
import examples.scala.events.OrderPlaced

class FireSensoryEventAndAwaitReceived(val baker: Baker) {

  def example(recipeInstanceId: String, orderPlaced: OrderPlaced): Unit = {
    val eventInstance = EventInstance.unsafeFrom(orderPlaced)
    val sensoryEventStatus = baker.fireSensoryEventAndAwaitReceived(recipeInstanceId, eventInstance)
  }
}

Wait for completion

awaitCompleted completes when additional sensory events are required to continue the process, or when the process has finished.

Note

Make sure to set a timeout smaller than the requestTimeout of your httpClient. Otherwise, you will see awaitCompleted() timeout prematurely.

package examples.java.application;

import com.ing.baker.runtime.javadsl.Baker;
import com.ing.baker.runtime.javadsl.EventInstance;
import examples.java.events.OrderPlaced;

import java.time.Duration;

public class AwaitCompleted {

    private final Baker baker;

    public AwaitCompleted(Baker baker) {
        this.baker = baker;
    }

    public void example(String recipeInstanceId, OrderPlaced orderPlaced) {
        var eventInstance = EventInstance.from(orderPlaced);
        baker.fireSensoryEventAndAwaitReceived(recipeInstanceId, eventInstance).join();
        baker.awaitCompleted(recipeInstanceId, Duration.ofSeconds(5)).join();
    }
}
package examples.kotlin.application

import com.ing.baker.runtime.javadsl.EventInstance
import com.ing.baker.runtime.kotlindsl.Baker
import examples.kotlin.events.OrderPlaced
import kotlin.time.Duration.Companion.seconds

class AwaitCompleted(private val baker: Baker) {

    suspend fun example(recipeInstanceId: String, orderPlaced: OrderPlaced) {
        val orderPlacedEvent = EventInstance.from(orderPlaced)
        baker.fireSensoryEventAndAwaitReceived(recipeInstanceId, orderPlacedEvent)
        baker.awaitCompleted(recipeInstanceId, timeout = 5.seconds)
    }
}
package examples.scala.application

import com.ing.baker.runtime.scaladsl.{Baker, EventInstance}
import examples.scala.events.OrderPlaced

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.DurationInt

class AwaitCompleted(val baker: Baker) {

  def example(recipeInstanceId: String, orderPlaced: OrderPlaced): Unit = {
    val eventInstance = EventInstance.unsafeFrom(orderPlaced)
    for {
      _ <- baker.fireSensoryEventAndAwaitReceived(recipeInstanceId, eventInstance)
      _ <- baker.awaitCompleted(recipeInstanceId, timeout = 5.seconds)
    } yield ()
  }
}

Wait for an event

awaitEvent completes when an event with the specified name appears in the list of fired events.

Note

Make sure to set a timeout smaller than the requestTimeout of your httpClient. Otherwise, you will see awaitEvent() timeout prematurely.

package examples.java.application;

import com.ing.baker.runtime.javadsl.Baker;
import com.ing.baker.runtime.javadsl.EventInstance;
import examples.java.events.OrderPlaced;

import java.time.Duration;

public class AwaitEvent {

    private final Baker baker;

    public AwaitEvent(Baker baker) {
        this.baker = baker;
    }

    public void example(String recipeInstanceId, OrderPlaced orderPlaced) {
        var eventInstance = EventInstance.from(orderPlaced);
        baker.fireSensoryEventAndAwaitReceived(recipeInstanceId, eventInstance).join();
        baker.awaitEvent(recipeInstanceId, "ExpectedEvent", Duration.ofSeconds(5)).join();
    }
}
package examples.kotlin.application

import com.ing.baker.runtime.javadsl.EventInstance
import com.ing.baker.runtime.kotlindsl.Baker
import examples.kotlin.events.OrderPlaced
import kotlin.time.Duration.Companion.seconds

class AwaitEvent(private val baker: Baker) {

    suspend fun example(recipeInstanceId: String, orderPlaced: OrderPlaced) {
        val orderPlacedEvent = EventInstance.from(orderPlaced)
        baker.fireSensoryEventAndAwaitReceived(recipeInstanceId, orderPlacedEvent)
        baker.awaitEvent(recipeInstanceId, "ExpectedEvent", timeout = 5.seconds)
    }
}
package examples.scala.application

import com.ing.baker.runtime.scaladsl.{Baker, EventInstance}
import examples.scala.events.OrderPlaced

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.DurationInt

class AwaitEvent(val baker: Baker) {

  def example(recipeInstanceId: String, orderPlaced: OrderPlaced): Unit = {
    val eventInstance = EventInstance.unsafeFrom(orderPlaced)
    for {
      _ <- baker.fireSensoryEventAndAwaitReceived(recipeInstanceId, eventInstance)
      _ <- baker.awaitEvent(recipeInstanceId, "ExpectedEvent", timeout = 5.seconds)
    } yield ()
  }
}

Inquiry

Baker allows you to query the state of a recipe instance at any given moment. To this end, Baker exposes a couple of different methods that allow you to fetch information about events, ingredients, and interactions from a running process.

package examples.java.application;

import com.ing.baker.runtime.javadsl.Baker;

public class InquiryExample {

    private final Baker baker;

    public InquiryExample(Baker baker) {
        this.baker = baker;
    }

    public void example(String recipeInstanceId) {
        var ingredient = baker.getIngredient(recipeInstanceId, "orderId").join();

        var ingredients = baker.getIngredients(recipeInstanceId).join();

        var events = baker.getEvents(recipeInstanceId).join();

        var eventNames = baker.getEventNames(recipeInstanceId).join();

        var recipeInstanceState = baker.getRecipeInstanceState(recipeInstanceId).join();
    }
}
package examples.kotlin.application

import com.ing.baker.runtime.kotlindsl.Baker

class InquiryExample(private val baker: Baker) {

    suspend fun example(recipeInstanceId: String) {
        val ingredient = baker.getIngredient(recipeInstanceId, "orderId")

        val ingredients = baker.getIngredients(recipeInstanceId)

        val events = baker.getEvents(recipeInstanceId)

        val eventNames = baker.getEventNames(recipeInstanceId)

        val recipeInstanceState = baker.getRecipeInstanceState(recipeInstanceId)
    }
}
package examples.scala.application

import com.ing.baker.runtime.scaladsl.Baker

class InquiryExample(val baker: Baker) {

  def example(recipeInstanceId: String): Unit = {
    val ingredient = baker.getIngredient(recipeInstanceId, "orderId")

    val ingredients = baker.getIngredients(recipeInstanceId)

    val events = baker.getEvents(recipeInstanceId)

    val eventNames = baker.getEventNames(recipeInstanceId)

    val recipeInstanceState = baker.getRecipeInstanceState(recipeInstanceId)
  }
}

Deprecated API

Deprecated

The methods described below are deprecated and will be removed in a future version. Please use the new API described above.

To trigger a Baker process you'll need to fire a sensory event. After firing an event, you may want to continue your asynchronous computation at one of four different moments:

  1. Right after the event was received, but before any interactions are executed.
  2. After all interactions have completed. At this point the process is either finished, or requires other sensory events to continue.
  3. You want to do something on both the previously mentioned moments.
  4. As soon one of the interactions fires a specific event.

To this end, the Baker interface exposes four different methods to fire events. We'll discuss each of those in more detail.

Fire event and resolve when received

This method returns a CompletableFuture<SensoryEventStatus>. It completes right after the event was received, but before any interactions are executed. The SensoryEventStatus is an enum containing information about the outcome of the event (Received, Completed, FiringLimitMet, etc).

package examples.java.application;

import com.ing.baker.runtime.javadsl.Baker;
import com.ing.baker.runtime.javadsl.EventInstance;
import examples.java.events.OrderPlaced;

public class FireEventAndResolveWhenReceived {

    private final Baker baker;

    public FireEventAndResolveWhenReceived(Baker baker) {
        this.baker = baker;
    }

    public void example(String recipeInstanceId, OrderPlaced orderPlaced) {
        var eventInstance = EventInstance.from(orderPlaced);
        var sensoryEventStatus = baker.fireEventAndResolveWhenReceived(recipeInstanceId, eventInstance).join();
    }
}
package examples.kotlin.application

import com.ing.baker.runtime.javadsl.EventInstance
import com.ing.baker.runtime.kotlindsl.Baker
import examples.kotlin.events.OrderPlaced

class FireEventAndResolveWhenReceived(private val baker: Baker) {

    suspend fun example(recipeInstanceId: String, orderPlaced: OrderPlaced) {
        val orderPlacedEvent = EventInstance.from(orderPlaced)
        val sensoryEventStatus = baker.fireEventAndResolveWhenReceived(recipeInstanceId, orderPlacedEvent)
    }
}
package examples.scala.application

import com.ing.baker.runtime.scaladsl.{Baker, EventInstance}
import examples.scala.events.OrderPlaced

class FireEventAndResolveWhenReceived(val baker: Baker) {

  def example(recipeInstanceId: String, orderPlaced: OrderPlaced): Unit = {
    val eventInstance = EventInstance.unsafeFrom(orderPlaced)
    val sensoryEventStatus = baker.fireEventAndResolveWhenReceived(recipeInstanceId, eventInstance)
  }
}

Fire event and resolve when completed

Returns a CompletableFuture<SensoryEventResult>. It completes when additional sensory events are required to continue the process, or when the process has finished. The SensoryEventResult contains the SensoryEventStatus and a list of all events names triggered as a result of this sensory event.

package examples.java.application;

import com.ing.baker.runtime.javadsl.Baker;
import com.ing.baker.runtime.javadsl.EventInstance;
import examples.java.events.OrderPlaced;

public class FireEventAndResolveWhenCompleted {

    private final Baker baker;

    public FireEventAndResolveWhenCompleted(Baker baker) {
        this.baker = baker;
    }

    public void example(String recipeInstanceId, OrderPlaced orderPlaced) {
        var eventInstance = EventInstance.from(orderPlaced);
        var sensoryEventResult = baker.fireEventAndResolveWhenCompleted(recipeInstanceId, eventInstance).join();
    }
}
package examples.kotlin.application

import com.ing.baker.runtime.javadsl.EventInstance
import com.ing.baker.runtime.kotlindsl.Baker
import examples.kotlin.events.OrderPlaced

class FireEventAndResolveWhenCompleted(private val baker: Baker) {

    suspend fun example(recipeInstanceId: String, orderPlaced: OrderPlaced) {
        val orderPlacedEvent = EventInstance.from(orderPlaced)
        val sensoryEventResult = baker.fireEventAndResolveWhenCompleted(recipeInstanceId, orderPlacedEvent)
    }
}
package examples.scala.application

import com.ing.baker.runtime.scaladsl.{Baker, EventInstance}
import examples.scala.events.OrderPlaced

class FireEventAndResolveWhenCompleted(val baker: Baker) {

  def example(recipeInstanceId: String, orderPlaced: OrderPlaced): Unit = {
    val eventInstance = EventInstance.unsafeFrom(orderPlaced)
    val sensoryEventResult = baker.fireEventAndResolveWhenCompleted(recipeInstanceId, eventInstance)
  }
}

Fire event

This method is useful if you want to do something after the event was received and after all interactions have completed. The method returns an EventResolutions object consisting of a CompletableFuture<SensoryEventStatus> and CompletableFuture<SensoryEventResult>. The former completes on receiving the event, the latter on completion of the interactions.

package examples.java.application;

import com.ing.baker.runtime.javadsl.Baker;
import com.ing.baker.runtime.javadsl.EventInstance;
import examples.java.events.OrderPlaced;

public class FireEvent {

    private final Baker baker;

    public FireEvent(Baker baker) {
        this.baker = baker;
    }

    public void example(String recipeInstanceId, OrderPlaced orderPlaced) {
        var eventInstance = EventInstance.from(orderPlaced);

        var eventResolutions = baker.fireEvent(recipeInstanceId, eventInstance);
        var sensoryEventStatus = eventResolutions.getResolveWhenReceived().join();
        var sensoryEventResult = eventResolutions.getResolveWhenCompleted().join();
    }
}
package examples.kotlin.application

import com.ing.baker.runtime.javadsl.EventInstance
import com.ing.baker.runtime.kotlindsl.Baker
import examples.kotlin.events.OrderPlaced

class FireEvent(private val baker: Baker) {

    suspend fun example(recipeInstanceId: String, orderPlaced: OrderPlaced) {
        val orderPlacedEvent = EventInstance.from(orderPlaced)

        val eventResolutions = baker.fireEvent(recipeInstanceId, orderPlacedEvent)
        val sensoryEventStatus = eventResolutions.resolveWhenReceived.await()
        val sensoryEventResult = eventResolutions.resolveWhenCompleted.await()
    }
}
package examples.scala.application

import com.ing.baker.runtime.scaladsl.{Baker, EventInstance}
import examples.scala.events.OrderPlaced

class FireEvent(val baker: Baker) {

  def example(recipeInstanceId: String, orderPlaced: OrderPlaced): Unit = {
    val eventInstance = EventInstance.unsafeFrom(orderPlaced)

    val eventResolutions = baker.fireEvent(recipeInstanceId, eventInstance)
    val sensoryEventStatus = eventResolutions.resolveWhenReceived
    val sensoryEventResult = eventResolutions.resolveWhenCompleted
  }
}

Fire event and resolve on event

This method returns a CompletableFuture<SensoryEventResult>. It completes when one of the interactions fires an event with a specified name.

package examples.java.application;

import com.ing.baker.runtime.javadsl.Baker;
import com.ing.baker.runtime.javadsl.EventInstance;
import examples.java.events.OrderPlaced;

public class FireEventAndResolveOnEvent {

    private final Baker baker;

    public FireEventAndResolveOnEvent(Baker baker) {
        this.baker = baker;
    }

    public void example(String recipeInstanceId, OrderPlaced orderPlaced) {
        var eventInstance = EventInstance.from(orderPlaced);
        var sensoryEventResult = baker.fireEventAndResolveOnEvent(recipeInstanceId, eventInstance, "ExpectedEvent").join();
    }
}
package examples.kotlin.application

import com.ing.baker.runtime.javadsl.EventInstance
import com.ing.baker.runtime.kotlindsl.Baker
import examples.kotlin.events.OrderPlaced

class FireEventAndResolveOnEvent(private val baker: Baker) {

    suspend fun example(recipeInstanceId: String, orderPlaced: OrderPlaced) {
        val orderPlacedEvent = EventInstance.from(orderPlaced)
        val sensoryEventResult = baker.fireEventAndResolveOnEvent(recipeInstanceId, orderPlacedEvent, "ExpectedEvent")
    }
}
package examples.scala.application

import com.ing.baker.runtime.scaladsl.{Baker, EventInstance}
import examples.scala.events.OrderPlaced

class FireEventAndResolveOnEvent(val baker: Baker) {

  def example(recipeInstanceId: String, orderPlaced: OrderPlaced): Unit = {
    val eventInstance = EventInstance.unsafeFrom(orderPlaced)
    val sensoryEventResult = baker.fireEventAndResolveWhenCompleted(recipeInstanceId, eventInstance)
  }
}