The subscriber layer of the EventEngine pipeline.
EventEngine is a schema-first event pipeline. Events are declared with
event_engine-event_definition,
compiled into a committed catalog, and emitted through the
event_engine runtime. The runtime
resolves each event to a processor by name, using the host's rules file.
This gem is one of those processors. It runs the subscribers you write in your app — either synchronously or in a background job.
gem "event_engine-subscribers"It registers itself at boot as the :inline and :background processors. You write
no wiring.
Subclass Base in app/subscribers, declare the event, implement #handle. Every
class in app/subscribers is loaded and registered when the app starts and again
after each code reload, so there is nothing else to wire.
class SendWelcomeEmail < EventEngine::Subscribers::Base
subscribes_to :lead_created
def handle(event)
UserMailer.welcome(event.payload[:email]).deliver_later
end
endevent is the EventEngine::Event the runtime built — event_name, payload,
metadata, occurred_at and the rest of the envelope.
Several subscribers may subscribe to the same event; each one's #handle is called.
In your app's config/event_rules.yml, name inline or background for the event:
events:
lead_created: inline # run subscribers synchronously, during emit
lead_converted: background # enqueue a job and return immediatelyThat is the whole configuration.
| rule | what happens |
|---|---|
inline |
every subscriber for the event runs synchronously inside emit |
background |
DispatchSubscribersJob is enqueued; subscribers run in a worker |
Choose background when the work is slow or failure-tolerant, inline when the
caller depends on it having happened.
MarketingEvents.lead_created(lead: lead)Nothing else is needed — the runtime resolves the rule, finds this gem's processor, and your subscribers run.
background enqueues DispatchSubscribersJob through Active Job, so it uses whatever
queue adapter your app has configured. The event is serialised to a hash and rebuilt
in the worker, so a subscriber receives the same EventEngine::Event either way.
Payloads become job arguments, so keep them serialisable — which they already are if they came from a compiled catalog.
If a rule names inline or background and this gem is not installed, the runtime
raises rather than dropping the event:
EventEngine::UnregisteredProcessorError: the rule for event :lead_created
(pack :marketing) names processor :inline, but no processor is registered
under that name
If an event is routed to inline or background and no subscriber is registered for
it, the app refuses to start and names each such event:
EventEngine::Subscribers::UnsubscribedEventsError: These events are routed to
subscribers but have none: hay_baled
The check runs once the app has started, after every class in app/subscribers is
registered. A subscriber anywhere else registers only once Rails has loaded its class,
so keep subscribers in app/subscribers.
A subscriber that refuses a change can only undo it when it runs inline, during the emit. A host that depends on that names the event packs whose events must run inline:
# config/application.rb
config.event_engine_subscribers.inline_packs = [:console]When the app starts, the gem then refuses to start when an event has no rule, when a
rule names a processor nothing registered, or when an event in a named pack is routed to
background. The last error names every such event. Events in other packs may still
run in the background. With no packs named, which is the default, the gem runs no inline
check.
DYB-Development/event_engine_example
is a minimal Rails app using this gem — two subscribers on one event to show fan-out,
one routed inline and one background, with an integration test covering both.
bin/setup
bundle exec rake testThe suite runs against test/dummy. If a sibling ../event_engine checkout exists it
is used automatically; otherwise the GitHub source is.
Available as open source under the terms of the MIT License.