Skip to content

On Clause

An On Clause specifies how to handle a particular kind of message or situation as part of the definition of a handler. An On Clause is associated with a specific message definition and contains statements that define the handling of that message by the handler's parent. The containing Processor is the recipient of the message and the sender of any statements that send messages.

Kinds of On Clause

Clause Handles
on command X A specific command message
on event X A specific event message
on query X A specific query message
on result X A specific result message
on init Creation and initialization — once, ever
on term Termination — once, ever
on activate Entity rehydration — every time
on passivate Entity eviction — every time
on other A message not otherwise handled

on init and on term bracket the whole life of a definition. on activate and on passivate bracket each residency: an entity that is evicted from memory and later rehydrated passivates and activates repeatedly without ever being initialized or terminated again.

handler OrderHandler is {
  on init      { do "load configuration" }
  on activate  { do "warm the pricing cache for this order" }
  on passivate { do "flush the pricing cache" }
  on term      { do "archive the order record" }
}

Binding the Handled Message

An on clause may bind a local name to the message it is handling, using ordinary type ascription — the same rule as let x: T = ... and a field declaration p1: String, read as "ord has type command PlaceOrder":

on ord: command PlaceOrder {
  when ord.total > MinimumOrder then
    yield event OrderPlaced(id = ord.id, total = ord.total)
  end
}

Within the body the bound name denotes the whole message; a dotted path reaches its fields. The binding is optional, so every model written without it parses to exactly the same structure.

Local name validation

  • A local name that shadows an outer definition is legal but draws a Warning
  • A binding whose name collides with a field of the message or state is legal — bare foo is the binding, foo.foo is the field — but draws a Warning about the overload
  • A local name that does not begin with a lowercase letter draws a StyleWarning, so camelCase like myCounter stays legal

Message Origins

An on clause may also name where the message came from, optionally binding a local name to the origin:

on command DoIt from context Other { ??? }
on command DoIt from di: context Other { ??? }

An origin may be an inlet, a processor, a user, or an epic.

Restrictions by Container

Several restrictions are enforced at parse time, so a violating clause cannot enter the model at all:

Container Rule
Projector Event-only: on command, on query and on record are rejected. on event and on result are valid.
on event (anywhere) require and error are forbidden — an event has already happened and must always be accepted.
on activate / on passivate Entity-only, and side-effect free: send, tell, yield, morph and become are rejected.
Adaptor A handler with no on other clause is an Error.

Shadowed clauses

Within one handler, two on clauses handling the same message make the later one unreachable. That draws a StyleWarning on the later clause. Clauses are keyed by their resolved message type where it resolves, so distinct spellings of the same message are caught.

Options

timeout (1 argument) and idempotent (0 arguments) may be set on an on clause's metadata.

Occurs In

  • Handlers — the handler to which the On clause is applied

Contains

  • Statement — specifies what should happen when the message arrives