Trailblazer 2.1: Activity, the new Operation!
In Trailblazer 2.1, we are introduced to a new concept: Activity.
Unlike Trailblazer 2.0, where Operation was king, activities have taken over as the main orchestrator of business logic. Good old operations are still there, but now they act as a wrapper around activities. Its one and the same, except activities are more powerful! Don’t worry though, its super easy to pick up and its backward compatibility makes switching a breaze.
So, let’s jump right in. What does an activity look like?
module Broadcasts::Cancel
extend Trailblazer::Activity::Railway()
module_function
def set_model(ctx, broadcast_id:, **)
ctx[:model] = Broadcast.find_by(id: broadcast_id)
end
def set_step_status(ctx, model:, **)
ctx[:step] = model.action.step.first
ctx[:step].status = 'pause'
ctx[:step].save
end
def set_broadcast_status(ctx, model:, **)
model.status = 'cancelled'
model.save
end
def set_queued_emails_status(ctx, step:, **)
step.queued_emails.update_all(status: 'cancelled', completed_at: Time.now)
end
def set_job_ids(ctx, action_funnel_step:, **)
ctx[:ids] = step.queued_emails.pluck(:job_id)
end
step method(:set_model)
step method(:set_step_status)
step method(:set_broadcast_status)
step method(:set_queued_emails_status)
step method(:set_job_ids)
merge!(Sidekiq::InvalidateJobs)
end
Here we have an activity that cancels a broadcast. What this code exactly does is not important for the purpose of this article, so lets just examine the activity itself:
- Activities are contained in modules compared to class defined operations.
Broadcasts::Cancel
module extendsTrailblazer::Activity::Railway()
. This is all you need to use activities.module_function
, a ruby function, is used to define “module methods” as if the module was a class.- steps are defined just the same as operations in trb 2.0, except now we use “ctx”, standing for context, instead of “options” as the first parameter.
merge!
copies steps from another operation (Sidekiq::InvalidateJobs
) and runs them as its own. Order matters!
And this is how you call the activity:
event, (ctx, *) = Broadcasts::Cancel.call(broadcast_id: params[:broadcast_id])
if event.to_h[:semantic] == :success
...
else
...
end
ctx
contains all the computed information from your activity. In this example, it would contain:model
,:step
, and:ids
- event contains the success or failure of the activity
That’s it! Keep in mind this is a simple operation doing a simple thing. There is much more that you can do with activities. But you get the gist of it…