Class: GoodJob::CronManager

Inherits:
Object
  • Object
show all
Defined in:
lib/good_job/cron_manager.rb

Overview

CronManagers enqueue jobs on a repeating schedule.

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(schedules = {}, start_on_initialize: false) ⇒ CronManager

Returns a new instance of CronManager.

Parameters:

  • schedules (Hash) (defaults to: {})
  • start_on_initialize (Boolean) (defaults to: false)


33
34
35
36
37
38
39
40
41
# File 'lib/good_job/cron_manager.rb', line 33

def initialize(schedules = {}, start_on_initialize: false)
  @running = false
  @schedules = schedules
  @tasks = Concurrent::Hash.new

  self.class.instances << self

  start if start_on_initialize
end

Class Attribute Details

.instancesArray<GoodJob::CronManagers>? (readonly)

List of all instantiated CronManagers in the current process.

Returns:

  • (Array<GoodJob::CronManagers>, nil)


15
# File 'lib/good_job/cron_manager.rb', line 15

cattr_reader :instances, default: [], instance_reader: false

Instance Attribute Details

#schedulesHash (readonly)

Job configuration to be scheduled

Returns:

  • (Hash)


29
30
31
# File 'lib/good_job/cron_manager.rb', line 29

def schedules
  @schedules
end

Class Method Details

.task_observer(time, output, thread_error) ⇒ Object

Task observer for cron task

Parameters:

  • time (Time)
  • output (Object)
  • thread_error (Exception)


21
22
23
24
25
# File 'lib/good_job/cron_manager.rb', line 21

def self.task_observer(time, output, thread_error) # rubocop:disable Lint/UnusedMethodArgument
  return if thread_error.is_a? Concurrent::CancelledOperationError

  GoodJob.on_thread_error.call(thread_error) if thread_error && GoodJob.on_thread_error.respond_to?(:call)
end

Instance Method Details

#create_task(cron_key) ⇒ Object

Enqueues a scheduled task

Parameters:

  • cron_key (Symbol, String)

    the key within the schedule to use



82
83
84
85
86
87
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
113
# File 'lib/good_job/cron_manager.rb', line 82

def create_task(cron_key)
  schedule = @schedules[cron_key]
  return false if schedule.blank?

  fugit = Fugit::Cron.parse(schedule.fetch(:cron))
  delay = [(fugit.next_time - Time.current).to_f, 0].max

  future = Concurrent::ScheduledTask.new(delay, args: [self, cron_key]) do |thr_scheduler, thr_cron_key|
    # Re-schedule the next cron task before executing the current task
    thr_scheduler.create_task(thr_cron_key)

    CurrentExecution.reset
    CurrentExecution.cron_key = thr_cron_key

    Rails.application.executor.wrap do
      schedule = thr_scheduler.schedules.fetch(thr_cron_key).with_indifferent_access
      job_class = schedule.fetch(:class).constantize

      job_set_value = schedule.fetch(:set, {})
      job_set = job_set_value.respond_to?(:call) ? job_set_value.call : job_set_value

      job_args_value = schedule.fetch(:args, [])
      job_args = job_args_value.respond_to?(:call) ? job_args_value.call : job_args_value

      job_class.set(job_set).perform_later(*job_args)
    end
  end

  @tasks[cron_key] = future
  future.add_observer(self.class, :task_observer)
  future.execute
end

#restart(timeout: nil) ⇒ Object

Stop and restart

Parameters:

  • timeout (Numeric, nil) (defaults to: nil)

    Unused but retained for compatibility



63
64
65
66
# File 'lib/good_job/cron_manager.rb', line 63

def restart(timeout: nil) # rubocop:disable Lint/UnusedMethodArgument
  shutdown
  start
end

#running?Boolean?

Tests whether the manager is running.

Returns:

  • (Boolean, nil)


70
71
72
# File 'lib/good_job/cron_manager.rb', line 70

def running?
  @running
end

#shutdown(timeout: nil) ⇒ Object

Stop/cancel any scheduled tasks

Parameters:

  • timeout (Numeric, nil) (defaults to: nil)

    Unused but retained for compatibility



53
54
55
56
57
58
59
# File 'lib/good_job/cron_manager.rb', line 53

def shutdown(timeout: nil) # rubocop:disable Lint/UnusedMethodArgument
  @running = false
  @tasks.each do |_cron_key, task|
    task.cancel
  end
  @tasks.clear
end

#shutdown?Boolean?

Tests whether the manager is shutdown.

Returns:

  • (Boolean, nil)


76
77
78
# File 'lib/good_job/cron_manager.rb', line 76

def shutdown?
  !running?
end

#startObject

Schedule tasks that will enqueue jobs based on their schedule



44
45
46
47
48
49
# File 'lib/good_job/cron_manager.rb', line 44

def start
  ActiveSupport::Notifications.instrument("cron_manager_start.good_job", cron_jobs: @schedules) do
    @running = true
    schedules.each_key { |cron_key| create_task(cron_key) }
  end
end