Created
August 6, 2023 15:08
-
-
Save kokorolx/b64df3c20d9f93adf278ac57e16fa594 to your computer and use it in GitHub Desktop.
Recurring Workers with Rails, Sidekiq and ice_cube
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
app/sidekiq/recurring_workers/base_job.rb | |
require 'sidekiq/api' | |
class RecurringWorkers::BaseJob | |
include Sidekiq::Job | |
sidekiq_options queue: "recurring_workers", retry: 3, backtrace: true | |
def self.schedule_all | |
# Pre-load all recurring workers | |
Dir[Rails.root.join("app/workers/recurring_workers/*.rb")].sort.each { |file| require file } | |
RecurringWorkers.constants.each do |class_name| | |
next if class_name == :BaseJob | |
RecurringWorkers.module_eval(class_name.to_s).schedule | |
end | |
end | |
# When a clas that inherits from RecurringWorkers::Base defines its #perform | |
# method, redefine it to wrap it in a with_rescheduling block | |
def self.method_added(method_name) | |
super | |
return unless method_name == :perform && !@redefining_method | |
@redefining_method = true | |
original = instance_method(:perform) | |
define_method(:perform_with_rescheduling) do |*args, &block| | |
with_rescheduling do | |
original.bind(self).call(*args, &block) | |
end | |
rescue StandardError => e | |
logger.error("#{self.class}##{__method__}: #{e.message}\n #{e.backtrace.join("\n")}") | |
end | |
alias_method :perform, :perform_with_rescheduling | |
@redefining_method = false | |
end | |
module ClassMethods | |
def schedule | |
if scheduled? | |
puts "#{self.name} already scheduled" | |
return false | |
end | |
perform_at(perform_at_timestamp) | |
puts "Scheduled #{self.name} to perform at #{perform_at_timestamp}" | |
end | |
# Schedule to run daily at midnight. See | |
# https://github.com/seejohnrun/ice_cube | |
def schedule_rules | |
IceCube::Schedule.new(Time.zone.now.midnight) do |schedule| | |
schedule.add_recurrence_rule IceCube::Rule.daily | |
end | |
end | |
private | |
def perform_at_timestamp | |
schedule_rules.next_occurrence | |
end | |
def scheduled_set | |
Sidekiq::ScheduledSet.new | |
end | |
def scheduled_jobs_for_class | |
scheduled_set.scan(self.name).select { |job| job.klass == self.name } | |
end | |
def scheduled? | |
scheduled_jobs_for_class.present? | |
end | |
end | |
module InstanceMethods | |
private | |
def re_schedule | |
self.class.schedule | |
end | |
def with_rescheduling | |
yield | |
ensure | |
re_schedule | |
end | |
def log_filename | |
"#{self.class.name.underscore.gsub('/', '_')}_#{Rails.env}" | |
end | |
def logger | |
filename = Rails.root.join("log/#{log_filename}.log").to_s | |
@logger ||= ::Logger.new(filename) | |
end | |
end | |
extend ClassMethods | |
include InstanceMethods | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# app/sidekiq/recurring_workers/expiry_notification_job.rb | |
class RecurringWorkers::ExpiryNotificationJob < RecurringWorkers::BaseJob | |
def perform | |
ExpiryNotificationService.process | |
end | |
def self.schedule_rules | |
# change to anytime that you want to run | |
# check more details here: https://github.com/kokorolx/ice_cube | |
IceCube::Schedule.new(Time.zone.now.change(hour: 15, min: 0, sec: 0)) do |schedule| | |
schedule.add_recurrence_rule IceCube::Rule.daily | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment