Module: Sourced

Defined in:
lib/sourced/message.rb,
lib/sourced.rb,
lib/sourced/sync.rb,
lib/sourced/react.rb,
lib/sourced/types.rb,
lib/sourced/decide.rb,
lib/sourced/evolve.rb,
lib/sourced/router.rb,
lib/sourced/worker.rb,
lib/sourced/decider.rb,
lib/sourced/version.rb,
lib/sourced/consumer.rb,
lib/sourced/projector.rb,
lib/sourced/supervisor.rb,
lib/sourced/configuration.rb,
lib/sourced/rails/railtie.rb,
lib/sourced/command_context.rb,
lib/sourced/backends/test_backend.rb,
lib/sourced/backends/sequel_backend.rb,
lib/sourced/rails/install_generator.rb,
lib/sourced/backends/active_record_backend.rb

Overview

A superclass and registry to define event types for example for an event-driven or event-sourced system. All events have an “envelope” set of attributes, including unique ID, stream_id, type, timestamp, causation ID, event subclasses have a type string (ex. ‘users.name.updated’) and an optional payload This class provides a ‘.define` method to create new event types with a type and optional payload struct, a `.from` method to instantiate the correct subclass from a hash, ex. when deserializing from JSON or a web request. and a `#follow` method to produce new events based on a previous event’s envelope, where the #causation_id and #correlation_id are set to the parent event ## Message registries Each Message class has its own registry of sub-classes. You can use the top-level Sourced::Message.from(hash) to instantiate all message types. You can also scope the lookup by sub-class.

## JSON Schemas Plumb data structs support ‘.to_json_schema`, so you can document all events in the registry with something like

Message.subclasses.map(&:to_json_schema)

Examples:


# Define event struct with type and payload
UserCreated = Message.define('users.created') do
  attribute :name, Types::String
  attribute :email, Types::Email
end

# Instantiate a full event with .new
user_created = UserCreated.new(stream_id: 'user-1', payload: { name: 'Joe', email: '...' })

# Use the `.from(Hash) => Message` factory to lookup event class by `type` and produce the right instance
user_created = Message.from(type: 'users.created', stream_id: 'user-1', payload: { name: 'Joe', email: '...' })

# Use #follow(payload Hash) => Message to produce events following a command or parent event
create_user = CreateUser.new(...)
user_created = create_user.follow(UserCreated, name: 'Joe', email: '...')
user_created.causation_id == create_user.id
user_created.correlation_id == create_user.correlation_id
user_created.stream_id == create_user.stream_id

class PublicCommand < Sourced::Message; end

DoSomething = PublicCommand.define('commands.do_something')

# Use .from scoped to PublicCommand subclass
# to ensure that only PublicCommand subclasses are accessible.
cmd = PublicCommand.from(type: 'commands.do_something', payload: { ... })

Defined Under Namespace

Modules: Backends, Consumer, Decide, Evolve, Rails, React, Sync, Types Classes: Command, CommandContext, Configuration, Decider, Error, Event, Message, Projector, Router, Supervisor, Worker

Constant Summary collapse

ConcurrentAppendError =
Class.new(Error)
ConcurrentAckError =
Class.new(Error)
DeciderInterface =
Types::Interface[:handled_commands, :handle_command]
ReactorInterface =
Types::Interface[:consumer_info, :handled_events, :handle_events]
UnknownMessageError =
Class.new(ArgumentError)
PastMessageDateError =
Class.new(ArgumentError)
VERSION =
'0.0.1'

Class Method Summary collapse

Class Method Details

.configObject



12
13
14
# File 'lib/sourced.rb', line 12

def self.config
  @config ||= Configuration.new
end

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

Yields:



16
17
18
19
20
# File 'lib/sourced.rb', line 16

def self.configure(&)
  yield config if block_given?
  config.freeze
  config
end

.message_method_name(prefix, name) ⇒ Object



22
23
24
# File 'lib/sourced.rb', line 22

def self.message_method_name(prefix, name)
  "__handle_#{prefix}_#{name.split('::').map(&:downcase).join('_')}"
end