Osy#betaRun it on Osyrin: osyrin.com

Reference / Function

[Interest] — the events a handler of every event cares about

[On] [Interest(nameof(<Fn>))] void <Name>(Event e) { … } · List<string> <Fn>() { … }

`[Interest(nameof(Triggers))]` beside the `[On]` of a handler of EVERY event names a function that answers which event types it cares about now — the ones a rule is on, the ones a subscription takes. An event that only such handlers hear, none of them caring about it, is never written: no outbox row, no delivery, no statement. The answer is kept between requests and dropped the moment a table it read is written, so a rule saved now is heard on the very next event.

preview2 examples compiled by CIfunctioneventscompositioncost

Summary#

A handler of Event hears everything — and so every event it could hear is written and delivered for it, even when it does nothing with most of them. [Interest] says which ones it actually cares about:

[On] [Interest(nameof(RuleTriggers))]
void RunRules(Event e) { … }

/// The events some rule that is on runs on.
List<string> RuleTriggers() { return Rule.Where(r => !r.Off).Select(r => r.When).ToList(); }

An event no handler cares about is dropped before anything is written. With no rules at all, the app pays for its events exactly what it paid before it had any.

Signature#

[On]
[Interest(nameof(<Fn>))]       // or [Interest("<Fn>")]
void <Name>(Event e) { … }

List<string> <Fn>() { … }      // beside the handler; takes nothing; the full type names of the events it cares about

Description#

What does the function answer?#

The full type names of the events the handler cares about — what typeof(TicketArrived).FullName and Events.Type(e) give, and what Events.Catalog() lists as Type. It is ordinary code: it reads the handler's own rows (rules, subscriptions), and may ask Events.Catalog() to turn names it stores into types.

When is it asked?#

At the commit that raised an event, before the outbox is written — but not every time. Its answer is KEPT, for the database it was read from, until a table it read is written (by anyone, on any node), and never longer than half a minute. So the first event after a rule is saved reads it again; every other event costs nothing to check. A commit that itself writes a table the answer read — a rule saved and an event raised in one piece of work — treats the handler as caring about every event for that commit, since the answer cannot see what has not committed yet.

What if another handler hears the event anyway?#

Then the event is written and delivered as always, and a handler of every event that does not care about it is not run on it — so it does not read its rules for it. A typed handler ([On] void H(TicketArrived e)) always hears its event, and so does a handler of every event with no [Interest].

What may it name?#

A function beside the handler that takes nothing and answers List<string>. Anything else is refused where it is written, saying what would do:

`[Interest]` on 'Misspelt' names 'Wached', and there is no function of that name beside it — it must take nothing and answer `List<string>`, the events the handler cares about. The functions here that do: `Watched`.
'Typed' hears `LampLit` only, so it is interested in nothing else already — `[Interest]` narrows a handler of EVERY event: `[On] [Interest(nameof(Triggers))] void Typed(Event e)`.

Examples#

Heard once a watch names it#

A handler of every event that cares only about the types a Watch row names.

entity Lamp {
  [MaxLength(40)] string Name = "";
  security { allow read, create, update when IsAnonymous || IsAuthenticated; }
}

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

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

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

[On] [Interest(nameof(Watched))]
void Remember(Event e) { new Heard { Type = Events.Type(e) }; }

/// The events some watch names — what Remember cares about.
List<string> Watched() { return Watch.Select(w => w.Type).ToList(); }

void Light(Lamp l) { Raise(new LampLit { Lamp = l }); }
[Test]
void A_raise_is_heard_only_once_a_watch_names_it() {
  var lamp = new Lamp { Name = "Porch" };
  Light(lamp);
  Background.Settle();
  Assert.Equal(0, Heard.Count());
  new Watch { Type = typeof(LampLit).FullName };
  Background.Settle();
  Light(lamp);
  Background.Settle();
  Assert.Equal(1, Heard.Count());
}

See also#

Related

[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…

Raise(e) — say that something happened

`Raise(e)` says that the event `e` happened — an instance of a class marked `[Event]`. It is written in the same commit…

[Event] — what happens to a record, declared once

An event is a class marked `[Event]`: something that happens to a record, declared once by the code that owns the…

[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…