Skip to content

Recipe DSL

Warning

The examples in this section are set up to demonstrate specific features of the recipe DSL. The snippets are not complete recipes. For example, some snippets only specify sensory events without any interactions, and vice versa.

Sensory events

Firing limit

Sensory events can be declared with or without firing limit. The firing limit determines how many times the event is allowed to be fired into the process. If you don't want to impose any limits, you have to explicitly declare the event as such. If left unspecified, the firing limit defaults to 1.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.Recipe;
import examples.java.events.FraudCheckCompleted;
import examples.java.events.OrderPlaced;
import examples.java.events.PaymentReceived;

public class RecipeWithSensoryEvents {

    public final static Recipe recipe = new Recipe("example")
        .withSensoryEventNoFiringLimit(OrderPlaced.class)
        .withSensoryEvent(PaymentReceived.class)
        .withSensoryEvent(FraudCheckCompleted.class, 5);
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import examples.kotlin.events.FraudCheckCompleted
import examples.kotlin.events.OrderPlaced
import examples.kotlin.events.PaymentReceived

@ExperimentalDsl
object RecipeWithSensoryEvents {
    val recipe = recipe(name = "example") {
        sensoryEvents {
            eventWithoutFiringLimit<OrderPlaced>()
            event<PaymentReceived>()
            event<FraudCheckCompleted>(maxFiringLimit = 5)
        }
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.scaladsl.{Event, Recipe}
import examples.scala.events.{FraudCheckCompleted, OrderPlaced, PaymentReceived}

object RecipeWithSensoryEvents {
  val recipe: Recipe = Recipe(name = "example")
    .withSensoryEvents(
      Event[OrderPlaced],
      PaymentReceived.event,
      FraudCheckCompleted.event
    )
}

Note

For Scala events the maxFiringLimit is set in the Event definition. An example event definition can be found in this section of the tutorial.

Event receive period

The period during which the process accepts sensory events. This is an optional parameter, defaults to accepting sensory events forever.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.Recipe;

import java.time.Duration;

public class RecipeWithEventReceivePeriod {

    public final static Recipe recipe = new Recipe("example")
        .withEventReceivePeriod(Duration.ofHours(5));
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import kotlin.time.Duration.Companion.hours

@ExperimentalDsl
object RecipeWithEventReceivePeriod {
    val recipe = recipe(name = "example") {
        eventReceivePeriod = 5.hours
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.scaladsl.Recipe

import scala.concurrent.duration.{FiniteDuration, HOURS}

object RecipeWithEventReceivePeriod {
  val recipe: Recipe = Recipe(name = "example")
    .withEventReceivePeriod(FiniteDuration.apply(5, HOURS))
}

Interactions

Custom name

By default, the name of the interaction matches the name of the interaction class. Optionally, you can specify your own name.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.InteractionDescriptor;
import com.ing.baker.recipe.javadsl.Recipe;
import examples.java.interactions.ShipOrder;

public class InteractionWithCustomName {

    public final static Recipe recipe = new Recipe("example")
        .withInteractions(
            InteractionDescriptor.of(ShipOrder.class, "ship-order")
        );
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import examples.kotlin.interactions.ShipOrder

@ExperimentalDsl
object InteractionWithCustomName {
    val recipe = recipe("example") {
        interaction<ShipOrder> {
            name = "ship-order"
        }
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.scaladsl.Recipe
import examples.scala.interactions.ShipOrder

object InteractionWithCustomName {
  val recipe: Recipe = Recipe("example")
    .withInteraction(
      ShipOrder.interaction
        .withName("ship-order")
    )
}

Maximum interaction count

By default, an interaction can be invoked an unlimited amount of times. Optionally, you can specify a limit.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.InteractionDescriptor;
import com.ing.baker.recipe.javadsl.Recipe;
import examples.java.interactions.ShipOrder;

public class RecipeWithMaxInteractionCount {

    public final static Recipe recipe = new Recipe("example")
        .withInteractions(
            InteractionDescriptor.of(ShipOrder.class)
                .withMaximumInteractionCount(1)
        );
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import examples.kotlin.interactions.ShipOrder

@ExperimentalDsl
object RecipeWithMaxInteractionCount {
    val recipe = recipe("example") {
        interaction<ShipOrder> {
            maximumInteractionCount = 1
        }
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.scaladsl.Recipe
import examples.scala.interactions.ShipOrder

object RecipeWithMaxInteractionCount {
  val recipe: Recipe = Recipe("example")
    .withInteraction(
      ShipOrder.interaction
        .withMaximumInteractionCount(1)
    )
}

Predefined ingredients

It's possible to register static ingredients to the interaction via predefined ingredients.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.InteractionDescriptor;
import com.ing.baker.recipe.javadsl.Recipe;
import examples.java.interactions.ShipOrder;

import java.math.BigDecimal;
import java.util.Map;

public class RecipeWithPredefinedIngredients {

    public final static Recipe recipe = new Recipe("example")
        .withInteractions(
            InteractionDescriptor.of(ShipOrder.class)
                .withPredefinedIngredients(
                    Map.of(
                        "shippingCostAmount", new BigDecimal("5.75"),
                        "shippingCostCurrency", "EUR"
                    )
                )
        );
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import examples.kotlin.interactions.ShipOrder

@ExperimentalDsl
object RecipeWithPredefinedIngredients {
    val recipe = recipe("example") {
        interaction<ShipOrder> {
           preDefinedIngredients {
               "shippingCostAmount" to "5.75".toBigDecimal()
               "shippingCostCurrency" to "EUR"
           }
        }
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.scaladsl.Recipe
import examples.scala.interactions.ShipOrder

object RecipeWithPredefinedIngredients {
  val recipe: Recipe = Recipe("example")
    .withInteraction(
      ShipOrder.interaction
        .withPredefinedIngredients(
          ("shippingCostAmount", BigDecimal("5.75")),
          ("shippingCostCurrency", "EUR")
        )
    )
}

Required events

Sometimes an interaction should only execute after a certain event has happened. To achieve this you can specify requiredEvents or requiredOneOfEvents.

All required events have to be available for the interaction to be executed. It works as a logical AND. In contrast, required one of events works as a logical OR. At least one of those events should be available before the interaction is executed.

In this example, the ShipOrder interaction will only execute if the FraudCheckCompleted and one of (or both) the PaymentReceived or UsedCouponCode events are available.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.InteractionDescriptor;
import com.ing.baker.recipe.javadsl.Recipe;
import examples.java.events.FraudCheckCompleted;
import examples.java.interactions.ShipOrder;

public class RecipeWithRequiredEvents {

    public final static Recipe recipe = new Recipe("example")
        .withInteractions(
            InteractionDescriptor.of(ShipOrder.class)
                .withRequiredEvent(FraudCheckCompleted.class)
                .withRequiredOneOfEventsFromName("PaymentReceived", "UsedCouponCode")
        );
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import examples.kotlin.events.FraudCheckCompleted
import examples.kotlin.events.PaymentReceived
import examples.kotlin.interactions.ShipOrder

@ExperimentalDsl
object RecipeWithRequiredEvents {
    val recipe = recipe("example") {
        interaction<ShipOrder> {
            requiredEvents {
                event<FraudCheckCompleted>()
            }
            requiredOneOfEvents {
                event<PaymentReceived>()
                event(name = "UsedCouponCode")
            }
        }
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.scaladsl.{Event, Recipe}
import examples.scala.events.{FraudCheckCompleted, PaymentReceived}
import examples.scala.interactions.ShipOrder

object RecipeWithRequiredEvents {
  val recipe: Recipe = Recipe("example")
    .withInteraction(
      ShipOrder.interaction
        .withRequiredEvent(
          FraudCheckCompleted.event
        )
        .withRequiredOneOfEvents(
          PaymentReceived.event,
          Event("UsedCouponCode")
        )
    )
}

Transform output events

It's possible to change the name of an output event. Optionally, you can also change names of ingredients.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.InteractionDescriptor;
import com.ing.baker.recipe.javadsl.Recipe;
import examples.java.events.OrderPlaced;
import examples.java.interactions.ShipOrder;

public class RecipeWithEventTransformation {

    public final static Recipe recipe = new Recipe("example")
        .withInteractions(
            InteractionDescriptor.of(ShipOrder.class)
                .withEventTransformation(OrderPlaced.class, "OrderCreated")
                .renameRequiredIngredient("customerId", "userId")
                .renameRequiredIngredient("productIds", "skus")
        );
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import examples.kotlin.events.OrderPlaced
import examples.kotlin.interactions.ShipOrder

@ExperimentalDsl
object RecipeWithEventTransformation {
    val recipe = recipe("example") {
        interaction<ShipOrder> {
           transformEvent<OrderPlaced>(newName = "OrderCreated") {
               "customerId" to "userId"
               "productIds" to "skus"
           }
        }
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.scaladsl.Recipe
import examples.scala.events.PaymentReceived
import examples.scala.interactions.ShipOrder

object RecipeWithEventTransformation {
  val recipe: Recipe = Recipe("example")
    .withInteraction(
      ShipOrder.interaction
        .withEventOutputTransformer(
          event = PaymentReceived.event,
          newEventName = "OrderCreated",
          ingredientRenames = Map.apply(
            ("customerId", "userId"),
            ("productIds", "skus")
          )
        )
    )
}

Override input ingredients

It's possible to change the names the input ingredients.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.InteractionDescriptor;
import com.ing.baker.recipe.javadsl.Recipe;
import examples.java.interactions.ShipOrder;

public class RecipeWithIngredientNameOverrides {

    public final static Recipe recipe = new Recipe("example")
        .withInteractions(
            InteractionDescriptor.of(ShipOrder.class)
                .renameRequiredIngredient("orderId", "orderNumber")
        );
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import examples.kotlin.interactions.ShipOrder

@ExperimentalDsl
object RecipeWithIngredientNameOverrides {
    val recipe = recipe("example") {
        interaction<ShipOrder> {
            ingredientNameOverrides {
                "orderId" to "orderNumber"
            }
        }
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.scaladsl.Recipe
import examples.scala.interactions.ShipOrder

object RecipeWithIngredientNameOverrides {
  val recipe: Recipe = Recipe("example")
    .withInteraction(
      ShipOrder.interaction
        .withOverriddenIngredientName("orderId", "orderNumber")
    )
}

Failure strategy

It's possible to define a failure strategy on interaction level. This failure strategy will only be used for this specific interaction. Interaction specific failure strategies take precedence over the default failure strategy. For all available failure strategies, see the error handling section.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.InteractionDescriptor;
import com.ing.baker.recipe.javadsl.InteractionFailureStrategy;
import com.ing.baker.recipe.javadsl.Recipe;
import examples.java.interactions.ShipOrder;

public class RecipeWithFailureStrategy {

    public final static Recipe recipe = new Recipe("example")
        .withInteractions(
            InteractionDescriptor.of(ShipOrder.class)
                .withFailureStrategy(
                        InteractionFailureStrategy.FireEvent("shippingFailed")
                )
        );
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import examples.kotlin.interactions.ShipOrder

@ExperimentalDsl
object RecipeWithFailureStrategy {
    val recipe = recipe("example") {
        interaction<ShipOrder> {
            failureStrategy = fireEventAfterFailure("shippingFailed")
        }
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.common.InteractionFailureStrategy
import com.ing.baker.recipe.scaladsl.Recipe
import examples.scala.interactions.ShipOrder

object RecipeWithFailureStrategy {
  val recipe: Recipe = Recipe("example")
    .withInteraction(
      ShipOrder.interaction
        .withFailureStrategy(
          InteractionFailureStrategy.FireEventAfterFailure(Some("shippingFailed"))
        )
    )
}

Recipe

Checkpoint events

Checkpoints are used to fire an event with a given name whenever certain preconditions are met. The preconditions are specified via requiredEvents or requiredOneOfEvents.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.CheckPointEvent;
import com.ing.baker.recipe.javadsl.Recipe;
import examples.java.events.FraudCheckCompleted;
import examples.java.events.PaymentReceived;

public class RecipeWithCheckpointEvent {

    public final static Recipe recipe = new Recipe("example")
        .withCheckpointEvent(
            new CheckPointEvent("CheckpointReached")
                .withRequiredEvents(
                        PaymentReceived.class,
                        FraudCheckCompleted.class
                )
        );
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import examples.kotlin.events.FraudCheckCompleted
import examples.kotlin.events.PaymentReceived

@ExperimentalDsl
object RecipeWithCheckpointEvent {
    val recipe = recipe("example") {
        checkpointEvent(eventName = "CheckpointReached") {
            requiredEvents {
                event<PaymentReceived>()
                event<FraudCheckCompleted>()
            }
        }
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.scaladsl
import com.ing.baker.recipe.scaladsl.Recipe
import examples.scala.events.{FraudCheckCompleted, PaymentReceived}

object RecipeWithCheckpointEvent {
  val recipe: Recipe = Recipe("example")
    .withCheckpointEvent(
      scaladsl.CheckPointEvent(
        name = "CheckpointReached",
        requiredEvents = Set.apply(
          PaymentReceived.event.name,
          FraudCheckCompleted.event.name
        )
      )
    )
}

Default failure strategy

The default failure strategy allows you to set a failure strategy for interactions that don't specify one explicitly. For all available failure strategies, see the error handling section.

package examples.java.recipes;

import com.ing.baker.recipe.javadsl.InteractionFailureStrategy;
import com.ing.baker.recipe.javadsl.Recipe;

public class RecipeWithDefaultFailureStrategy {

    public final static Recipe recipe = new Recipe("example")
        .withDefaultFailureStrategy(
            InteractionFailureStrategy.FireEvent("recipeFailed")
        );
}
package examples.kotlin.recipes

import com.ing.baker.recipe.kotlindsl.ExperimentalDsl
import com.ing.baker.recipe.kotlindsl.recipe
import examples.kotlin.interactions.ShipOrder

@ExperimentalDsl
object RecipeWithDefaultFailureStrategy {
    val recipe = recipe("example") {
        defaultFailureStrategy = fireEventAfterFailure("recipeFailed")
    }
}
package examples.scala.recipes

import com.ing.baker.recipe.common.InteractionFailureStrategy
import com.ing.baker.recipe.scaladsl.Recipe

object RecipeWithDefaultFailureStrategy {
  val recipe: Recipe = Recipe("example")
    .withDefaultFailureStrategy(
      InteractionFailureStrategy.FireEventAfterFailure(Some("recipeFailed"))
    )
}