Module: EventEngine

Defined in:
lib/event_engine.rb,
lib/event_engine/event.rb,
lib/event_engine/engine.rb,
lib/event_engine/railtie.rb,
lib/event_engine/version.rb,
lib/event_engine/reference.rb,
lib/event_engine/the_local.rb,
lib/event_engine/schema_diff.rb,
lib/event_engine/dsl_compiler.rb,
lib/event_engine/event_schema.rb,
lib/event_engine/process_type.rb,
lib/event_engine/configuration.rb,
lib/event_engine/event_builder.rb,
lib/event_engine/schema_catalog.rb,
lib/event_engine/schema_registry.rb,
lib/event_engine/event_definition.rb,
lib/event_engine/handler_registry.rb,
lib/event_engine/subject_registry.rb,
lib/event_engine/definition_loader.rb,
lib/event_engine/schema_drift_guard.rb,
lib/event_engine/event_schema_dumper.rb,
lib/event_engine/event_schema_loader.rb,
lib/event_engine/event_schema_merger.rb,
lib/event_engine/event_schema_writer.rb,
app/jobs/event_engine/application_job.rb,
lib/event_engine/lifecycle_definition.rb,
lib/event_engine/schema_compatibility.rb,
lib/event_engine/event_definition/inputs.rb,
lib/event_engine/event_definition/schemas.rb,
app/models/event_engine/application_record.rb,
lib/event_engine/event_definition/payloads.rb,
app/helpers/event_engine/application_helper.rb,
app/mailers/event_engine/application_mailer.rb,
lib/event_engine/event_definition/validation.rb,
lib/generators/event_engine/install_generator.rb,
app/controllers/event_engine/application_controller.rb

Overview

EventEngine is the schema-first core of the event pipeline.

Events are defined via a Ruby DSL and compiled into a canonical schema file. At boot, a helper method is installed on this module for each registered event (e.g. EventEngine.cow_fed(cow: cow)); the helper validates inputs, builds an Event, and dispatches it to registered handlers by level. Companion gems (e.g. event_engine-delivery) register handlers to process the events.

Examples:

Define, build, and dispatch an event

EventEngine.register_handler(MyHandler, levels: :all)
EventEngine.cow_fed(cow: cow, occurred_at: Time.current)

Defined Under Namespace

Modules: ApplicationHelper, Companion, DefinitionLoader, Generators, ProcessType, Reference Classes: ApplicationController, ApplicationJob, ApplicationMailer, ApplicationRecord, Configuration, DslCompiler, Engine, Event, EventBuilder, EventDefinition, EventSchema, EventSchemaDumper, EventSchemaLoader, EventSchemaMerger, EventSchemaWriter, HandlerRegistry, LifecycleDefinition, Railtie, SchemaCatalog, SchemaCompatibility, SchemaDiff, SchemaDriftGuard, SchemaRegistry, SubjectRegistry

Constant Summary collapse

VERSION =
"0.1.0"

Class Method Summary collapse

Class Method Details

.boot_from_schema!(schema_path:, registry:) ⇒ EventSchema

Loads a schema file, populates the registry, and installs helper methods. Called automatically by the engine at Rails boot.

Parameters:

  • schema_path (String, Pathname)

    path to the compiled schema file

  • registry (SchemaRegistry)

    the registry to populate

Returns:



109
110
111
112
113
114
115
116
117
118
# File 'lib/event_engine.rb', line 109

def boot_from_schema!(schema_path:, registry:)
  event_schema = EventSchemaLoader.load(schema_path)

  registry.reset!
  registry.load_from_schema!(event_schema)

  install_helpers(registry: registry)

  event_schema
end

.compiled_schema_registrySchemaRegistry

Compiles event definitions from source into a registry. Used by rake tasks for schema drift detection.

Returns:



177
178
179
180
181
182
183
184
# File 'lib/event_engine.rb', line 177

def compiled_schema_registry
  DefinitionLoader.ensure_loaded!
  definitions = EventDefinition.descendants
  compiled = DslCompiler.compile(definitions)
  registry = SchemaRegistry.new
  registry.load_from_schema!(compiled)
  registry
end

.configurationConfiguration

Returns the current configuration instance.

Returns:



43
44
45
# File 'lib/event_engine.rb', line 43

def configuration
  @configuration ||= Configuration.new
end

.configure {|config| ... } ⇒ Object

Yields the configuration for modification.

Examples:

EventEngine.configure do |config|
  config.logger = Rails.logger
end

Yield Parameters:



54
55
56
# File 'lib/event_engine.rb', line 54

def configure
  yield(configuration)
end

.define_subjects(&block) ⇒ Object



66
67
68
# File 'lib/event_engine.rb', line 66

def define_subjects(&block)
  subject_registry.instance_eval(&block)
end

.dispatch(event) ⇒ Object



95
96
97
# File 'lib/event_engine.rb', line 95

def dispatch(event)
  handler_registry.dispatch(event)
end

.enriched_metadata(call_site_metadata) ⇒ Object



74
75
76
77
78
79
# File 'lib/event_engine.rb', line 74

def ()
  defaults = 
  return  if defaults.nil?

  defaults.merge( || {})
end

.evaluated_metadata_defaultsObject



81
82
83
84
85
86
87
88
89
# File 'lib/event_engine.rb', line 81

def 
  callable = configuration.
  return nil unless callable

  callable.call
rescue => error
  configuration.logger&.error("EventEngine metadata_defaults raised: #{error.message}")
  nil
end

.file_schema_registrySchemaRegistry

Loads the committed schema file into a registry. Used by rake tasks for schema drift detection.

Returns:



190
191
192
193
194
195
# File 'lib/event_engine.rb', line 190

def file_schema_registry
  loaded = EventSchemaLoader.load(Rails.root.join("db/event_schema.rb"))
  registry = SchemaRegistry.new
  registry.load_from_schema!(loaded)
  registry
end

.handler_registryObject



58
59
60
# File 'lib/event_engine.rb', line 58

def handler_registry
  @handler_registry ||= HandlerRegistry.new
end

.install_helpers(registry:) ⇒ Object

Installs singleton helper methods on the EventEngine module for each event in the registry. Previous helpers are removed first.

Parameters:



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/event_engine.rb', line 124

def install_helpers(registry:)
  _installed_event_helpers.each do |method_name|
    singleton_class.remove_method(method_name) if singleton_class.method_defined?(method_name)
  end
  _installed_event_helpers.clear

  registry.events.each do |event_name|
    schema = registry.schema(event_name)

    required = schema.required_inputs
    optional = schema.optional_inputs

    define_singleton_method(event_name) do |**args|
      event_version = args.delete(:event_version)
      occurred_at = args.delete(:occurred_at)
       = args.delete(:metadata)
      idempotency_key = args.delete(:idempotency_key)
      aggregate_type = args.delete(:aggregate_type)
      aggregate_id = args.delete(:aggregate_id)
      aggregate_version = args.delete(:aggregate_version)

      input_keys = required + optional
      inputs = args.slice(*input_keys)

      missing = required - inputs.keys
      raise ArgumentError, "Missing required inputs: #{missing.join(', ')}" if missing.any?

      unknown = args.keys - input_keys
      raise ArgumentError, "Unknown inputs: #{unknown.join(', ')}" if unknown.any?

      schema = registry.schema(event_name, version: event_version)
      attrs = EventBuilder.build(schema: schema, data: inputs)
      attrs[:occurred_at] = occurred_at || Time.current
      attrs[:metadata] = EventEngine.()
      attrs[:idempotency_key] = idempotency_key || SecureRandom.uuid
      attrs[:aggregate_type] = aggregate_type
      attrs[:aggregate_id] = aggregate_id
      attrs[:aggregate_version] = aggregate_version
      attrs[:process_type] = schema.process_type
      attrs[:subject] = schema.subject
      attrs[:domain] = schema.domain

      EventEngine.dispatch(Event.new(**attrs))
    end

    _installed_event_helpers << event_name
  end
end

.register_handler(handler, levels:) ⇒ Object



91
92
93
# File 'lib/event_engine.rb', line 91

def register_handler(handler, levels:)
  handler_registry.register(handler, levels: levels)
end

.reset_handlers!Object



99
100
101
# File 'lib/event_engine.rb', line 99

def reset_handlers!
  handler_registry.clear!
end

.reset_subjects!Object



70
71
72
# File 'lib/event_engine.rb', line 70

def reset_subjects!
  @subject_registry = nil
end

.subject_registryObject



62
63
64
# File 'lib/event_engine.rb', line 62

def subject_registry
  @subject_registry ||= SubjectRegistry.new
end