All Jobs have a built in interface for executing code before and after a
#perform
method. This is a general purpose strategy for tasks like
preemption, monitoring, rate limiting, failure notifications, etc.
A before hook is one strategy to rate limit jobs which might have negative consequences for running too frequently.
When a Job run needs to be delayed consider using #retry_later or #fail.
class NotifyUserJob < Mosquito::QueuedJob
param user_id : Int32
before do
# prevent spamming a user with notifications
fail if (Time.utc - user.last_notification_sent) < 2.minutes
end
def perform
user.last_notification_sent = Time.utc
user.notify!
end
def user : User
found_user = UserService.fetch user_id
fail unless found_user
found_user
end
end
The mosquito built in Rate Limiting module makes use of a before hook to halt and reschedule a job run.
An after hook doesn’t have the ability to prevent a job from running. It gets run regardless of job success, even if a job throws an exception, or is never run due to a before hook.
class MonitoredJob < Mosquito::QueuedJob
def perform
System.long_running_failure_prone_task
end
after do
System.send_admin_email("the long running task failed again") unless succeeded?
end
end
If a job fails implicitly by throwing an exception it is stored in the #exception
variable and can be inspected in an after hook:
class FailingJob < Mosquito::QueuedJob
def perform
raise IndexError.new("Index out of bounds")
end
after do
if failed && thrown_exception = exception
System.send_admin_email("Job failed with an exception. #{thrown_exception.message}")
end
end
end