Osy#betaRun it on Osyrin: osyrin.com

Reference / Function

Raise(e) — say that something happened

Raise(new <EventClass> { <Member> = …, … })

`Raise(e)` says that the event `e` happened — an instance of a class marked `[Event]`. It is written in the same commit as the work around it, and every `[On]` handler of its class hears it after that commit. An event no handler hears costs nothing: no row, no statement.

preview2 examples compiled by CIfunctioneventscomposition

Summary#

Raise(new QuoteAccepted { Quote = q }) says the event happened. It returns at once; nothing hears it yet. When the work around it commits, every [[function-on|[On]]] handler of QuoteAccepted — in the app, or in any package that sees the class — runs, after that commit.

public void AcceptQuote(Quote q) {
  q.Status = QuoteStatus.Accepted;
  Raise(new QuoteAccepted { Quote = q });      // heard once this work has committed
}

Raise is the [[function-event|[Event]]]'s. Workflow.Raise and <Workflow>.Raise<Event> are a different thing: they move ONE workflow run along (Raising a workflow event).

Signature#

void Raise(<an instance of a class marked [Event]>)

Description#

When does a handler hear it?#

After the commit that carries it — never before, and never for work that did not commit. The event is written in the same transaction as the rows around it, so the two land together or not at all; then its handlers run, in process straight after the commit. If the process stops between the two, the platform delivers it later from what was committed.

A handler therefore reads the record as it stands after the work — a quote raised as accepted is read accepted.

And inside a workflow's step?#

Then its handlers run when the step has ended, not at the first commit inside it. One step of a run — a start, an event's arm, an entry, a timer's body — may commit more than once: a function it calls may commit, and so does a function marked [[function-commits-alone|[CommitsAlone]]]. Every event those commits carry is kept until the step is over and then delivered together, in the order raised.

So a handler never meets a run half-way through the step that raised to it, and it follows that a row a handler writes lands after the rows the body went on to write in the same step — even when the event was raised in a function whose own unit of work committed first. If something must be on record at that earlier moment, write it in the function that raises, not in a handler.

What if the work is rolled back?#

Then it was never raised. Raise moves with the rows written around it: a try that throws takes back what it wrote and the events it raised alike, and a function that fails raises nothing.

What does it cost?#

An event no handler hears costs nothing — the compiler knows every handler, so a Raise of one nobody hears writes no row and sends no statement. One somebody hears costs the same however many handlers hear it: its row is written with the commit, then read, run and marked delivered once — what each handler writes is that handler's own cost.

A handler of EVERY event (a rule engine, a webhook sender) says which events it cares about with [[function-interest|[Interest]]] — and an event heard only by such handlers, none of which cares about it now, costs nothing either: no row, no delivery, no statement. With no rule and no subscription, an app using them pays for its events exactly what it paid before it had any.

Several events raised by one piece of work are written in one statement and delivered in ONE transaction: read together, each record they share read once, one commit. Each further event adds its own mark and whatever its handlers read and write — not another transaction.

Raising does not cost the person a request: it all happens on the server, after the request's own commit.

How long is it kept?#

The platform keeps a delivered event a week — long enough for an operator to see what a handler did not do, short enough that it never grows with the app's age or holds an event's personal content past its use — and then lets it go, with what was recorded against it. A record's history is not kept here: a timeline that shows what happened to a record keeps its own, for as long as its own setting says (The RecordTimeline kit — what happened to a record, on its own timeline).

Who may raise one?#

Any code that can see the class — the kit that declares it, an app or package that uses that kit. The event row is the platform's and nobody's grant creates one, so no caller can forge an event: it exists only because code raised it.

What must the argument be?#

An instance of an [Event] class. Anything else is refused where it is written:

`NotAnEvent` is not an event — `Raise(…)` takes an instance of a class marked `[Event]`. Mark it: `[Event] public
sealed class NotAnEvent { … }` …

Examples#

Raised inside a try that fails#

The try takes back the order it placed and the event it raised; the function goes on and commits what it wrote after.

entity Order {
  [Required, MaxLength(40)] string Code;
  security { allow read, create when IsAnonymous || IsAuthenticated; }
}

entity Heard {
  [Required, MaxLength(100)] string What;
  security { allow read, create when IsAnonymous || IsAuthenticated; }
}

[Event]
public sealed class OrderPlaced { public Order Order; }

[On]
void Note(OrderPlaced e) { new Heard { What = "placed " + e.Order.Code }; }

string PlaceTwo() {
  var kept = new Order { Code = "kept" };
  Raise(new OrderPlaced { Order = kept });
  try {
    var o = new Order { Code = "dropped" };
    Raise(new OrderPlaced { Order = o });
    throw new ValidationException("not this one");
  }
  catch (ValidationException) { }
  return "done";
}
[Test]
void The_try_took_back_its_event() {
  PlaceTwo();
  Background.Settle();
  Assert.Equal(["placed kept"], Heard.Select(h => h.What).ToList());
}

See also#

Related

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

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

try / catch / finally

Handles a fault. C#'s syntax, including typed catches, catch filters and finally. The rows written inside a try block…

UnitOfWork

Every body accumulates its writes in a unit of work rather than sending them one at a time. UnitOfWork.Commit() makes…

Raising a workflow event

Raise a typed event on the run bound to an entity, from anywhere — an ordinary server function, a webhook handler, a…