Documentation previewThese docs are actively being built. Some pages may change as the framework and examples are finalized.
Skip to content

Events

An Event is a typed fact that something happened.

Use events for fan-out and decoupled reactions. Use queues and jobs for durable background work, retries, delays, timeouts, and worker lifecycle.

When To Use Events

QuestionGuidance
Use this whenSomething happened and one or more subscribers may react to that fact.
Avoid this whenThe work needs durability, retries, queue selection, delays, timeout policy, or worker scaling.
Start withinproc events for local same-process fan-out.
Upgrade toTransport-backed events when subscribers must run in other processes or hosts.

Generated Package

Generated event code lives in:

text
internal/events

Create an event type:

bash
forj make:event UserRegistered

make:event generates a plain payload type and topic constant. It does not add a Wire provider because event payloads are created at publish time, not constructed once as App dependencies.

Create subscribers separately:

bash
forj make:subscriber users:registered

make:subscriber creates a handler object and registers it in the App-owned event subscriber injector. Use --bus <name> when the subscriber should listen on a named bus configured by EVENTS_<NAME>_DRIVER.

Use domain.past_tense topics, such as users.created or invoices.paid. Review the generated topic constant before other code depends on it. See Naming Conventions for the full naming map.

Event Shape

go
type UserRegisteredEvent struct {
	UserID string `json:"user_id"`
}

func (UserRegisteredEvent) Topic() string {
	return "users.registered"
}

Topics should be stable when other code or infrastructure depends on them.

Publishing

Publish through the generated App event bus:

go
err := app.Bus().WithContext(ctx).Publish(UserRegisteredEvent{
	UserID: user.ID,
})

In services, prefer injecting the event bus or a small publisher wrapper instead of reaching through global state.

Drivers

Compile-time support:

text
EVENTS_SUPPORTED_DRIVERS=inproc,redis

Runtime selection:

text
EVENTS_DRIVER=inproc
EVENTS_AUDIT_DRIVER=redis
EVENTS_INPROC_WORKERS=0
EVENTS_INPROC_BUFFER=1024

inproc is process-local and non-durable. Use distributed drivers when events need to cross process boundaries.

Regeneration

After changing supported drivers or named event buses, use the normal build path:

bash
forj build

Dev Loop

During forj dev, the generated build watcher normally runs forj build for you.

Use focused generation only when you intentionally want to refresh events without a full build:

bash
forj generate --events

Common Mistakes

Common mistakes

  • Do not use events as durable job transport.
  • Do not assume in-process events are visible across processes.
  • Do not publish events for every private method call.
  • Do not use unstable topic names.
  • Do not make subscribers silently swallow important failures.

Next Steps