The main goal of this gem is to provide a simple way to publish events and subscribe to them. This gem was heavily inspired by the Wisper and WisperSidekiq gems.
This gem WON'T work with ruby 3.2 or 3.1 due to dependencies with Zeitwerk-2.7.1. It's recommended to use ruby 3.3 or newer. jRuby is also not tested, you should try yourself.
gem 'sidekiq_events', github: 'patrickemuller/sidekiq-events'It's also possible to enable/disable the gem in the application by setting the initializer for it:
SidekiqEvents::Configuration.configure do |config|
config.enabled = ENV.fetch('SIDEKIQ_EVENTS_ENABLED', true)
endEmitting new events is easy, and can be done like the following example:
First, you create a new event class:
class MyEventName < ::SidekiqEvents::Event
# Optional, but also possible, you can overwrite the sidekiq options for the event
sidekiq_options queue: 'should_be_this_queue', retry: 999
# Define the custom attributes that will be used in the event, otherwise
# it will use the default attributes from the parent class
# Attributes are provided from the dry-types gem
# attribute :_id, Types::String
# attribute :_event_source, Types::String
# attribute :emitted_at, Types::String
# attribute :attributes, Types::Array
attribute :order_id, Types::Integer
attribute :order_uuid, Types::String
# You can also overwrite the event_name for the event class
# This is useful when you have multiple events that should fall
# under the same "category" of events
def self.event_name
'my_event_name'
end
endThen, you can publish the event like this:
event = MyEventName.new(order_id: 1, order_uuid: 'abcd1234')
# Call methods can be shortened to .() instead of call.()
SidekiqEvents::Emitter.(event)And then, finally, you define which classes will handle the emitted events. This can be used for any class that process information. Any class with "handle" will listen to those events and process them using the attributes you provided.
The same applies for background jobs. You can have a class class YouBackgroundJob < ActiveJob::Base
that will handle the events you emitted, and process them in the background.
class SomeOrderCommand
include SidekiqEvents::Handler
def call(order_identifier, some_named_argument: nil)
order = ::Order.find_by(id: order_identifier).or(::Order.find_by(uuid: order_identifier))
# .... your implementation
order
end
handle ::MyEventName do |event|
self.(event.order_id || event.order_uuid)
end
# OR
handle [::MyEventName, ::AnotherEvent], sidekiq_options: { queue: 'events', retry: 123 } do |event|
self.(event.order_id || event.order_uuid)
end
endIf you need to emit multiple events at once, you can use the MultiEmitter class. Here is an example:
# Define your events
class EventOne < ::SidekiqEvents::Event
attribute :data, Types::String
end
class EventTwo < ::SidekiqEvents::Event
attribute :info, Types::String
end
# Create instances of your events
event_one = EventOne.new(data: 'example data')
event_two = EventTwo.new(info: 'example info')
# Emit multiple events at once
results = Sidekiq::Events::MultiEmitter.call([event_one, event_two])
# Inspect the results
results.each do |result|
puts "Event: #{result[:event].class.name}, Result: #{result[:result]}"
endIt's possible to identify the origin of the event, and which attributes were used to emit the event.
# Build the event and it's attributes
event = MyEventName.new(order_id: 1, order_uuid: 'abcd1234')
# Initialize the emitter
emitter = SidekiqEvents::Emitter.new
# Emit the event
emitter.(event)
# Inspecting the event attributes
event.attributes
#=> {:order_id=>1, :order_uuid=>"abcd1234", :_id=>"3580d0d8-9312-4fa8-9a3c-91e3288f0701", :_event_source=>nil, :emitted_at=>nil}
# Inspecting the emitter attributes
emitter.attributes
#=> {:order_id=>1, :order_uuid=>"abcd1234", :_id=>"3580d0d8-9312-4fa8-9a3c-91e3288f0701", :_event_source=>"SidekiqEvents::Emitter", :emitted_at=>Tue, 28 Jan 2025 16:12:44 -0800, :_event_class=>"MyEventName"}
# And after you emit the event, you can inspect the event attributes again to see the changes
# It will contain the same attributes from the emitter, and you can use that to
# check where the event was emitted from, useful for debugging
event.attributes
#=> {:order_id=>1, :order_uuid=>"abcd1234", :_id=>"3580d0d8-9312-4fa8-9a3c-91e3288f0701", :_event_source=>"SidekiqEvents::Emitter", :emitted_at=>Tue, 28 Jan 2025 16:12:44 -0800, :_event_class=>"MyEventName"}This gem uses multiple ruby versions and gemfiles to test the compatibility with more recent versions of ruby. If you wish to pull this gem locally and make changes, you'll have to install the gems for a specific ruby version.
Let's say you're trying to test/improve it agains the ruby 3.3. You can install the dependencies like this:
BUNDLE_GEMFILE=ruby3.3.gemfile bundle install
OR
bundle install --gemfile="ruby3.3.gemfile"There is another way, involving installing direnv and creating a .envrc file
with the following content, but this is not support by default since this would be an Environment specific kind of setup.
export BUNDLE_GEMFILE=ruby3.3.gemfileIt's a bit annoying to do it like that, but this is the only way to check multiple Ruby/Gemfile versions and make sure the Gem work with as many versions as possible.
There is no default template for opening Github issues or pull request, just make sure you include all information needed to debug/understand the issue you're facing or the feature you're trying to implement. Be gentle, respect others, and provide meaningful information to those who will review your code (with test scenarios). Other than that, be a good person and help others to improve the gem!
- Add support for debouncing events so they don't process more than one time
- Add support for the Zeitwerk autoloader