Module: Gouda::Scheduler
- Defined in:
- lib/gouda/scheduler.rb
Defined Under Namespace
Classes: Entry
Class Method Summary collapse
-
.build_scheduler_entries_list!(cron_table_hash = nil) ⇒ Object
Takes in a Hash formatted with cron entries in the format similar to good_job, and builds a table of scheduler entries.
-
.enqueue_next_scheduled_workload_for(finished_workload) ⇒ Object
Once a workload has finished (doesn’t matter whether it raised an exception or completed successfully), it is going to be passed to this method to enqueue the next scheduled workload.
-
.entries ⇒ Object
Returns the list of entries of the scheduler which are currently known.
-
.known_scheduler_keys ⇒ Object
Returns the set of known scheduler keys that may be present in the workloads table and are defined by the current entries.
-
.upsert_workloads_from_entries_list! ⇒ Object
Will upsert (‘INSERT … ON CONFLICT UPDATE`) workloads for all entries which are in the scheduler entries table (the table needs to be read or hydrated first using `build_scheduler_entries_list!`).
Class Method Details
.build_scheduler_entries_list!(cron_table_hash = nil) ⇒ Object
Takes in a Hash formatted with cron entries in the format similar to good_job, and builds a table of scheduler entries. A scheduler entry references a particular job class name, the set of arguments to be passed to the job when performing it, and either the interval to repeat the job after or a cron pattern. This method does not insert the actual Workloads into the database but just builds the table of the entries. That table gets consulted when workloads finish to determine whether the workload that just ran was scheduled or ad-hoc, and whether the subsequent workload has to be enqueued.
If no table is given the method will attempt to read the table from Rails application config from ‘[:gouda]`.
The table is a Hash of entries, and the keys are the names of the workload to be enqueued - those keys are also used to ensure scheduled workloads only get scheduled once.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/gouda/scheduler.rb', line 88 def self.build_scheduler_entries_list!(cron_table_hash = nil) Gouda.logger.info "Updating scheduled workload entries..." if cron_table_hash.nil? # An empty hash indicates that an empty crontab will be loaded config_from_rails = Rails.application.config.try(:gouda) cron_table_hash = if config_from_rails.present? config_from_rails.dig(:cron).to_h if config_from_rails.dig(:enable_cron) elsif Gouda.config.enable_cron Gouda.config.cron end return unless cron_table_hash end defaults = {cron: nil, interval_seconds: nil, kwargs: nil, args: nil} @cron_table = cron_table_hash.map do |(name, cron_entry_params)| # `class` is a reserved keyword and a method that exists on every Ruby object so... cron_entry_params[:job_class] ||= cron_entry_params.delete(:class) params_with_defaults = defaults.merge(cron_entry_params) Entry.new(name: name, **params_with_defaults) end @known_scheduler_keys = Set.new(@cron_table.map(&:scheduler_key)) @cron_table end |
.enqueue_next_scheduled_workload_for(finished_workload) ⇒ Object
Once a workload has finished (doesn’t matter whether it raised an exception or completed successfully), it is going to be passed to this method to enqueue the next scheduled workload
120 121 122 123 124 125 126 127 128 |
# File 'lib/gouda/scheduler.rb', line 120 def self.enqueue_next_scheduled_workload_for(finished_workload) return unless finished_workload.scheduler_key timer_table = @cron_table.to_a.index_by(&:scheduler_key) timer_entry = timer_table[finished_workload.scheduler_key] return unless timer_entry Gouda.enqueue_jobs_via_their_adapters([timer_entry.build_active_job]) end |
.entries ⇒ Object
Returns the list of entries of the scheduler which are currently known. Normally the scheduler will hold the list of entries loaded from the Rails config.
134 135 136 |
# File 'lib/gouda/scheduler.rb', line 134 def self.entries @cron_table || [] end |
.known_scheduler_keys ⇒ Object
Returns the set of known scheduler keys that may be present in the workloads table and are defined by the current entries.
142 143 144 |
# File 'lib/gouda/scheduler.rb', line 142 def self.known_scheduler_keys @known_scheduler_keys || Set.new end |
.upsert_workloads_from_entries_list! ⇒ Object
Will upsert (‘INSERT … ON CONFLICT UPDATE`) workloads for all entries which are in the scheduler entries table (the table needs to be read or hydrated first using `build_scheduler_entries_list!`). This is done in a transaction. Any workloads which have been previously inserted from the scheduled entries, but no longer have a corresponding scheduler entry, will be deleted from the database. If there already are workloads with the corresponding scheduler key they will not be touched and will be performed with their previously-defined arguments.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/gouda/scheduler.rb', line 154 def self.upsert_workloads_from_entries_list! table_entries = @cron_table || [] # Remove any cron keyed workloads which no longer match config-wise. # We do this to keep things clean (but it is not enough, an extra guard is needed in Workload checkout) known_keys = table_entries.map(&:scheduler_key).uniq Gouda::Workload.transaction do # We do this to keep things a bit clean Gouda::Workload.where.not(scheduler_key: known_keys).delete_all # Insert the next iteration for every "next" entry in the crontab. active_jobs_to_enqueue = table_entries.filter_map(&:build_active_job) Gouda.logger.info "#{active_jobs_to_enqueue.size} job(s) to enqueue from the scheduler." enqjobs = Gouda.enqueue_jobs_via_their_adapters(active_jobs_to_enqueue) Gouda.logger.info "#{enqjobs.size} scheduled job(s) enqueued." end end |