/ ruby

Introducing KittyEvents

During the Christmas break me and Mike were discussing a new feature at Product Hunt. The feature required scheduling an ActiveJobs when a user signs up, votes or submits a comment.

There is SignUp object which handles user registration. So scheduling a new background job there is quite simple:

module SignUp
  # ... handle user sign up

  def after_sign_up(user)
    WelcomeEmailWorker.perform_later(user)
    WelcomeTweetWorker.perform_later(user)
    SyncProfileImageWorker.perform_later(user)
    NewFancyFeatureWorker.perform_later(user) # <- new worker
  end
end

Unfortunately after_sign_up method was becoming quite large ☹️
Now imagine having to add NewFancyFeatureWorker to 10 other places ?

Those issues pushed us to create a simple wrapper around ActiveJobs, which we call KittyEvents.

Now in SignUp there is just one trigger for an "event":

module SignUp
  # ... handle user sign up

  def after_sign_up(user)
    ApplicationEvents.trigger(:user_signup, user)
  end
end

And there is a central place, where events are mapped to ActiveJobs Workers:

# config/initializers/application_events.rb
module ApplicationEvents
  extend KittyEvents

  event :user_signup, [
    WelcomeEmailWorker,
    WelcomeTweetWorker,
    SyncProfileImageWorker,
    NewFancyFeatureWorker, # <- new worker
  ]

  # ... other events
end

When an event is triggered, all ActiveJobs Workers for this events are scheduled and executed.

Another bonus, is when using KittyEvents, you only make a single Redis call to trigger any number of events. This shaves off precious milliseconds when using KittyEvents in request.