events

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: BSD-2-Clause Imports: 6 Imported by: 0

Documentation

Overview

Package events is the event-handler registry an object exposes to report what it did, for the things a caller wants to observe but the frame path does not carry: a summary being applied, a socket failing to open, a worker becoming ready.

An object declares the events it raises with Register, once, at construction. A caller then attaches handlers to a declared name with Add. Attaching to a name the object never declared is a mistake the registry reports rather than accepts, so a typo in an event name is caught instead of silently never firing.

An event is either synchronous or asynchronous, fixed when it is declared. A synchronous event runs its handlers inline, in the order they were added, and Call returns only once they have all finished; the object raising it is therefore waiting on them. An asynchronous event queues its handlers and Call returns straight away, leaving the object free to carry on. Cleanup waits for the handlers still queued or running.

The queue behind an asynchronous event is ordered, and one handler runs at a time. That matters: a handler is very often accumulating something, and it would otherwise see two firings of the same event in either order, or see them at once and have to lock against itself. So a handler observes the events of one object in the order that object raised them, and never runs beside another handler of the same object.

It is stricter in one place: a handler that blocks holds up the handlers queued behind it. A blocking handler is worth avoiding for that reason.

A handler that panics is reported and does not bring down the object that raised the event, nor stop the other handlers for it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Handler

type Handler func(ctx context.Context, source any, args ...any)

Handler is called when the event it is attached to fires. source is the object that raised the event, and args are the event's own arguments, whose number and types belong to that event. See On for a typed single-argument handler, which is the shape of every event that carries one value.

type HandlerID

type HandlerID uint64

HandlerID identifies a handler that was added, so it can be removed again. Go functions are not comparable, so a handler cannot be removed by passing the same function back; Add returns this instead.

func On

func On[T any](r *Registry, name string, fn func(ctx context.Context, value T)) HandlerID

On attaches a typed handler to an event carrying a single value, which is the shape of most of them, and returns the id that removes it again.

It is Add with the value already read out of the arguments, so a handler is written against what the event carries rather than against a slice of any. A firing that carries something else is reported and skipped, since a handler that cannot read its own event would otherwise do so silently.

events.On(&worker.Registry, workers.EventJobCompleted,
    func(ctx context.Context, result jobcontext.GroupResponse) { … })

func OnSignal

func OnSignal(r *Registry, name string, fn func(ctx context.Context)) HandlerID

OnSignal attaches a handler to an event that carries nothing, and returns the id that removes it again. Such an event says only that something happened: a pipeline went idle, a heartbeat stopped arriving.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry holds the events an object declares and the handlers attached to them. Embed it in the object that raises the events:

type Summarizer struct {
    events.Registry
    …
}

func New() *Summarizer {
    s := &Summarizer{}
    s.Register("on_summary_applied", false)
    return s
}

The zero value is ready to use. It is safe for concurrent use.

func (*Registry) Add

func (r *Registry) Add(name string, h Handler) HandlerID

Add attaches h to the event named name and returns the id that removes it again. Handlers run in the order they were added.

Adding to a name that was never declared with Register attaches nothing and is reported: the event would otherwise never fire and the caller would have no way to tell. The returned id is then zero, which Remove ignores.

func (*Registry) Call

func (r *Registry) Call(ctx context.Context, name string, source any, args ...any)

Call fires the event named name, passing source and args to every handler attached to it. Firing an event that was never declared does nothing, which is what lets an object raise an event unconditionally whether or not anything declared interest in it.

For a synchronous event Call runs the handlers inline and returns once they have all finished. For an asynchronous one it queues them and returns straight away; they run one at a time, in the order they were queued, and Cleanup waits for them.

Call never blocks on an asynchronous event, so a handler is free to raise another event on the same object.

func (*Registry) Cleanup

func (r *Registry) Cleanup(ctx context.Context)

Cleanup waits for the handlers of asynchronous events that are still queued or running. Call it when the object raising the events is done with, so a handler is not left running past the thing it was observing.

Do not call it from a handler: it would be waiting for itself.

func (*Registry) Register

func (r *Registry) Register(name string, sync bool)

Register declares an event this object raises. sync fixes how its handlers run: inline and awaited when true, each on its own goroutine when false.

Call it once per event, at construction. Declaring the same name twice is reported and leaves the first declaration in place.

func (*Registry) Remove

func (r *Registry) Remove(name string, id HandlerID)

Remove detaches the handler Add returned id for. It is a no-op if the event was never declared, or the handler was already removed, or id is zero.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL