Event, State, Transition: What Your Journey Reacts To

Event, State, Transition: What Your Journey Reacts To

Concept

Three different things travel under the word “trigger”. An event is a fact with a timestamp: a product was added to a cart at 14:02, and that will always have happened. A state is what is currently true about a customer given the events so far, and sometimes given the events that have not arrived: this customer has an unresolved cart, has not bought since, is identifiable and has consented to reminders. A transition is the moment a state changes, when the customer becomes eligible for a reminder or stops being eligible because the purchase came in. A well-designed journey is fed by events, triggers on transitions and checks states before it acts, and each of those three needs a different kind of support from the stack.

Why it matters

Mixing them up produces behaviour that looks like a bug in the journey when the fault sits in the model. Trigger on an event and the flow fires every time it happens, so three additions to the same cart produce three reminders. Trigger on a state and the flow keeps firing for as long as the state holds, or fires once when a nightly job flips a flag and then never resets. Many of the use cases that matter most are defined by something that did not happen, such as a purchase that never followed the cart, and an absence can only be detected by something that owns a timer, knows when to stop waiting and knows what to do with a purchase that arrives late. States also have a freshness, and it is set by how they are computed rather than by how fast events are ingested. Adobe’s computed attributes illustrate the trade clearly, since a lookback of up to 24 hours refreshes hourly and a lookback of six months refreshes monthly. That is a sensible design for a lifetime value score and the wrong one for suppressing a message after a purchase, which is why the batch versus event-driven choice has to be made per state, and why the slowest step between the event and the decision sets the real speed of the journey.

A simple example

A shopper adds a jacket to her cart at 14:00 and leaves. The event is recorded instantly. The journey’s rule says that after two hours with no purchase she becomes eligible for a reminder, so at 16:00 a transition fires and the reminder is scheduled for 16:05. At 15:30, however, she bought the jacket in a store. The store purchase is a perfectly good event, but it reaches the profile through the point-of-sale feed that loads overnight, so at 16:00 her state still reads unresolved cart and she receives a reminder for something she already owns. Every component worked as designed. The failure is that the state the journey checked depended on a source that updates once a day, and nobody compared that rhythm with the use case’s deadline.

The architecture view

A timeline for one customer. Events sit on the top line, a cart addition at 14:00 and a store purchase at 15:30. The state band below shows the cart as unresolved until the purchase reaches the profile the next morning. A transition marker at 16:00 fires the reminder while the purchase is still in transit.

The purchase happened in time. It reached the state too late, and the journey trusted the state.

The placement question is where state lives and who keeps it current. In the patterns, a CEP carrying its own data holds event, state and trigger in one place, which is why Pattern B handles real-time use cases well within its own channels, while a composable stack has to carry state across a junction between systems and needs streaming, monitoring and replay to do it reliably. For most lifecycle programmes either works. For suppression after a purchase, the state has to be updated within the use case’s deadline by every source that can resolve it.

The mistake I often see

The recurring error is modelling states as daily flags and then triggering journeys on them as if they were events. The warehouse recomputes cart_abandoner at two in the morning, the journey listens for the flag to turn true and fires at two in the morning for carts abandoned the previous afternoon, and when the flag fails to reset after a purchase the customer re-enters the next night. The related error is judging a platform’s speed by its ingestion latency. Events can land in milliseconds while the state that matters waits for a batch job, and the customer only ever experiences the slowest step in that chain.

Go deeper

This node sits between batch versus event-driven, which is about what starts a message, and what decisioning is, which is about choosing what to do once it starts. States are built from customer attributes on a resolved identity, and when a state goes wrong, explaining why a customer got a message is how you find out where. For the longer history of why schedules gave way to events, read Batch-and-Blast, Part 1.

Sources

Platform documentation

  • Adobe Experience League, Computed attributes overview. Lookback windows from hours to six months, with refresh rates from hourly to monthly.
Open full size