# [OncePerDelivery] — a read made once for every event of a delivery

> `[OncePerDelivery]` on a function that reads makes it answer once per delivery: the events one commit raised are delivered together, and a handler that calls it for each of them gets the first call's answer for the same arguments — so a rule engine reads its rules once for the batch, not once per event. Outside a delivery it simply runs.

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

## Summary        {#summary}
What one commit raises is delivered together — a ticket arriving, being queued, being assigned is ONE delivery. A
handler of every event that reads its rules for each event would read them three times; marked `[OncePerDelivery]`,
the read is made once and every event's handler is handed that answer:

```osy syntax
[OncePerDelivery]
List<Rule> SavedRules(string subject) { return Rule.Where(r => r.Subject == subject).ToList(); }
```

## Signature      {#signature}
```osy syntax
[OncePerDelivery]
<Type> <Name>(<params>) { … }     // answers something; called by a handler, or by what a handler calls
```

## Description    {#description}

### What is remembered?   {#remembered}
The answer, per set of arguments — strings, numbers, yes-or-no, Guids, dates and records (by id). A call
with any other kind of argument is not remembered: it simply runs. A list it answers is handed to each caller as their
own copy, so a handler adding to it does not change what the next event's handler gets; the records in it are the same
records, read on the delivery's own unit of work.

### For how long?   {#lifetime}
For one delivery — the events of one commit (or of one workflow step) delivered together. The next delivery reads again.
So the function should READ what the delivery itself does not change: rules, subscriptions, settings. What a handler
writes during the delivery is not in an answer remembered before it.

### Outside a delivery?   {#outside}
An ordinary call: a page, a test or the hourly clock calling the same function reads every time.

### What is refused?   {#refusals}
A function that answers nothing, a handler, an action or a test, and a method of a class:

```text
`[OncePerDelivery]` remembers what a function ANSWERS for the rest of a delivery — 'RemembersNothing' answers nothing, so there is nothing to remember. Put it on the function that reads: `[OncePerDelivery] List<Rule> SavedRules() { … }`.
```

## Examples       {#examples}

### Three events, one read   {#example}
One commit raises three events; each handler run reads the notes through `Notes()`, which is read once between them.

```osy title="a handler that reads its notes once for the delivery" test app=function-once-per-delivery
entity Lamp {
  [MaxLength(40)] string Name = "";
  security { allow read, create, update when IsAnonymous || IsAuthenticated; }
}

entity Note {
  [MaxLength(100)] string Text = "";
  security { allow read, create when IsAnonymous || IsAuthenticated; }
}

entity Heard {
  [MaxLength(200)] string Says = "";
  security { allow read, create when IsAnonymous || IsAuthenticated; }
}

[Event] public sealed class LampLit { public Lamp Lamp; }

[On]
void Remember(Event e) { new Heard { Says = Events.Type(e) + " with " + Notes().Count + " notes" }; }

[OncePerDelivery]
List<Note> Notes() { return Note.ToList(); }

void LightThrice(Lamp l) {
  Raise(new LampLit { Lamp = l });
  Raise(new LampLit { Lamp = l });
  Raise(new LampLit { Lamp = l });
}
```

```osy title="every event's handler is handed the notes" run app=function-once-per-delivery
[Test]
void Every_event_of_the_delivery_reads_the_same_notes() {
  new Note { Text = "bright" };
  var lamp = new Lamp { Name = "Porch" };
  Background.Settle();
  LightThrice(lamp);
  Background.Settle();
  Assert.Equal(3, Heard.Count(h => h.Says == "LampLit with 1 notes"));
}
```

## See also       {#see-also}
- [[On] — hear an event, after the commit that raised it](https://osysharp.com/reference/function/on/) — hearing an event, and when events are delivered together
- [[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
- [Raise(e) — say that something happened](https://osysharp.com/reference/function/raise/) — what raising an event costs
