After discussion with @jodosha, we decided that this library should look like another gem.
Also, we think that hanami-events should use different adapters and be without a global state.
Why different adapters?
I think hanami events should be a library for building Event-Driven Architecture. In this case, a library should work with different hanami project instances:
In this case, we can provide different transport layers for a event storage like:
- Memory
- Postgres
- Kafka
- Kinesis
- etc
And that’s why we need to replace wispers gem as an adapter.
From which hanami events should be?
I think that we need to split all logic to 3 different parts:
- Broadcaster
- Subscriber
- Routing
All these parts should be without a global state. And here my ideas about API for all this.
Broadcaster
events = Hanami::Events.new(:adapter)
events.broadcast('user.created', user: user)
Subscriber
kafka_events = Hanami::Events.new(:kafka)
memory_events = Hanami::Events.new(:memory)
memory_events.subscribe('user.signup', Mailer)
# or in class
class Signup
inclide Hanami::Events::Subscriber
subscribe_to memory_events, 'user.signup'
subscribe_to kafka_events, 'user.signup'
def call(payload)
# ...
end
end
Also, I think we should have an ability for subscribing to all events:
kafka_events = Hanami::Events.new(:kafka)
kafka_events.listen do |event|
event.name # => 'user.signup'
event.payload # => { ... }
end
Routing
Routing should route all events and call specific code for each one. It will be helpful for manage all events in one place (look like HTTP routers):
class WebHandler < Hanami::Events::Handler
on('user.created') { |payload| UserRepository.new.create(payload) }
on('user.updated') { |payload| payload }
end
class AnaliticHandler < Hanami::Events::Handler
on('*', AnaliticSender)
on('user.*') { |payload| payload }
on('user.signup') { |payload| payload }
end
class NotificationHandler < Hanami::Events::Handler
on('user.created') { |payload| payload }
on('post.created') { |payload| payload }
end
class EventRouting < Hanami::Events::Routing
mount UserHandler, Hanami.app?(:user_events) # load specific handlers for instance
mount AnaliticHandler
mount NotificationHandler
end
events = Hanami::Events.new(:adapter)
events.listen { |event| EventRouter.new.resolve(event) }
Plan
We will start work on proof of concept for this idea. It’s mean that we will implement only broadcaster and simple subscriber without routing and other features.