# [On] — hear an event, after the commit that raised it

> `[On]` on a function makes it a HANDLER of the event its one parameter is. Every handler of an event — in the app and in every package that sees it — runs after the commit that raised the event, with the app's authority, in one order the compiler fixes; one that throws has its writes discarded and is recorded, and the others still run. One that loses a race with another writer is run again. A handler that would run twice in one chain of events is cut, and that is recorded too. `[On] void H(Event e)` hears every event.

<!-- id: function-on · area: function · stability: preview · html: https://osysharp.com/reference/function/on/ -->

## Summary        {#summary}
A handler is an ordinary function with `[On]`, taking the event:

```osy syntax
[On]
void WinOnAccept(QuoteAccepted e) {
  if (e.Quote.Opportunity != null) { MarkWon(e.Quote.Opportunity); }
}
```

It runs once the work that raised the event has committed. A kit may hear the events of a kit it depends on, and an
app hears every kit's — nobody registers anything; the compiler finds every `[On]` in the app and its packages.

## Signature      {#signature}
```osy syntax
[On]                 // hears the event its one parameter is
[Order(10)]          // optional — lower runs first; none is 100
void <Name>(<EventClass> e) { … }

[On]                 // hears EVERY event — the app's and every package's
void <Name>(Event e) { … }
```

## Description    {#description}

### In what order do handlers run?   {#order}
One order, fixed when the app compiles, never by file or load order:

1. `[Order(n)]`, lower first — a handler with none is at 100, so kits that leave gaps of 10 below it run first;
2. then by package: a package before the packages that use it, the app last;
3. then by full name.

### A handler of every event   {#every}
A handler whose parameter is `Event` itself hears every event, of every class — what a timeline, a rule engine or
webhooks need, since they work on events they have never heard of. It asks [`Events.*`](https://osysharp.com/reference/function/event/) what each one
is, and `Events.Delivery()` where it stands: the event's `Id`, the `Root` of its cascade, its `Depth`, when it was
`RaisedAt`, and the `Cause` an action that raised it was run under. It is never cut from a cascade for having run
earlier in it: it hears what it caused, by design, and is held to the depth limit like any other.

Hearing every event is not free: each one it hears is written and delivered. When it only acts on SOME of them — the
ones a rule is on, the ones a subscription takes — say which with [[function-interest|`[Interest]`]], and an event it
does not care about is not written for it at all. A read it makes for every event can be made once for all the events
one commit raised with [[function-once-per-delivery|`[OncePerDelivery]`]].

### When does it run?   {#when}
After the commit that raised the event — in process, straight after it, so a handler's work is there on the next line.
A workflow's step commits more than once (a run's `Start {}` before its first state is entered), so an event raised in
a step is delivered when the step — and every run its commit started — is done: a handler never meets a run half-way.
All of one event's handlers commit together, with the event marked delivered, so their work lands once — and the
events one piece of work raised (a commit, or a workflow step and every run it started) are delivered together, in the
order they were raised, in one transaction: a ticket that raises three events costs one delivery, not three. A handler
of the second event sees what the first event's handlers did, exactly as it would after their commit.

### What if a handler fails?   {#failure}
Its writes are discarded, the failure is recorded with the event — which handler, and what it said — and the
handlers after it still run. One handler's fault never takes the others' work with it. It is not run again: a fault
in its code would fail again, and a second run would repeat what it did before it threw.

The one exception is a LOST RACE — another writer changed a row the handler changed, first. That is not a fault, so the
handler is run again, reading the row as it now stands, a few times; only one that keeps losing is recorded.

When events are delivered together and one of them cannot land — a handler loses a race, or a write is refused only at
the commit — nothing of the batch is kept, and each event is delivered on its own, exactly as above. So a failing
handler never takes another event's work with it, and is recorded against its own event.

### What if handlers raise events that come back?   {#cycles}
Each event carries the handlers that ran on the way to it. A handler already on that path is not run again — that is a
loop — and the cut is recorded on the event it would have run on. A chain more than eight handlers deep is cut too.

### Whose authority does a handler run with?   {#authority}
The APP's, as a workflow body does: it runs after the person's request has ended, so there is no caller to run as. A
kit's `deny` still holds it — a handler is held to every package's write denies except its own package's. To act as a
person, run an [[function-action|`[Action]`]] as them: what that action raises belongs to this event's cascade, so a
rule set off by an event cannot set itself off again.

### What may a handler look like?   {#shape}
A top-level function with exactly one parameter, an `[Event]` class in sight (or `Event`), returning nothing — nobody waits for its
answer. A package's handler may be `internal`: the platform calls it, and nothing else can. Anything else is refused
where it is written:

```text
'TwoParams' hears an event, so it takes exactly ONE parameter — the event: `[On] void TwoParams(QuoteAccepted e)`.
An event handler returns nothing — nobody waits for its answer, because it runs after the commit that raised the event.
`[Order]` places an event handler among the others — 'NoOn' has no `[On]`, so there is nothing for it to place.
```

## Examples       {#examples}

### Three handlers, and the middle one fails   {#example}
`[Order]` places them; the second throws, its write is discarded, and the first and third still run.

```osy title="ordered handlers, one of them failing" test app=function-on
entity Ticket {
  [Required, MaxLength(100)] string Subject;
  [MaxLength(200)] string Trail = "";
  security { allow read, create, update when IsAnonymous || IsAuthenticated; }
}

[Event("Ticket closed")]
public sealed class TicketClosed { public Ticket Ticket; }

void Close(Ticket t) { Raise(new TicketClosed { Ticket = t }); }

[On] [Order(10)]
void First(TicketClosed e) { e.Ticket.Trail = e.Ticket.Trail + "first;"; }

[On] [Order(20)]
void Second(TicketClosed e) {
  e.Ticket.Trail = e.Ticket.Trail + "second;";
  throw new ValidationException("the second one fails");
}

[On] [Order(30)]
void Third(TicketClosed e) { e.Ticket.Trail = e.Ticket.Trail + "third;"; }
```

```osy title="the failure takes only its own write" run app=function-on
[Test]
void A_failing_handler_leaves_the_others_their_work() {
  var t = new Ticket { Subject = "Printer jammed" };
  Close(t);
  Background.Settle();
  Assert.Equal("first;third;", Ticket.Single().Trail);
}
```

## See also       {#see-also}
- [[Event] — what happens to a record, declared once](https://osysharp.com/reference/function/event/) — declaring an event
- [Raise(e) — say that something happened](https://osysharp.com/reference/function/raise/) — raising one, and what it costs
- [[Action] — what an app offers to be done, by name](https://osysharp.com/reference/function/action/) — something a person or a rule may do, run under their security
- [try / catch / finally](https://osysharp.com/reference/function/try-catch/) — how a failing handler's writes are discarded
- [[Interest] — the events a handler of every event cares about](https://osysharp.com/reference/function/interest/) — a handler of every event says which it cares about
- [[OncePerDelivery] — a read made once for every event of a delivery](https://osysharp.com/reference/function/once-per-delivery/) — a read made once for every event of a delivery
