Class: GoodJob::Capsule

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

Overview

A GoodJob::Capsule contains the resources necessary to execute jobs, including a Scheduler, Poller, Notifier, and CronManager. GoodJob creates a default capsule on initialization.

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(configuration: nil) ⇒ Capsule

Returns a new instance of Capsule.

Parameters:



19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/good_job/capsule.rb', line 19

def initialize(configuration: nil)
  @configuration = configuration
  @startable = true
  @started_at = nil
  @mutex = Mutex.new

  @shared_executor = GoodJob::SharedExecutor.new
  @tracker = GoodJob::CapsuleTracker.new(executor: @shared_executor)
  @lower_thread_priority = nil

  self.class.instances << self
end

Class Attribute Details

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

List of all instantiated Capsules in the current process.

Returns:



12
# File 'lib/good_job/capsule.rb', line 12

cattr_reader :instances, default: Concurrent::Array.new, instance_reader: false

Instance Attribute Details

#trackerObject (readonly)

Returns the value of attribute tracker.



16
17
18
# File 'lib/good_job/capsule.rb', line 16

def tracker
  @tracker
end

Instance Method Details

#create_thread(job_state = nil) ⇒ Boolean?

Creates an execution thread(s) with the given attributes.

Parameters:

Returns:

  • (Boolean, nil)

    Whether the thread was created.



105
106
107
108
# File 'lib/good_job/capsule.rb', line 105

def create_thread(job_state = nil)
  start if startable?
  @multi_scheduler&.create_thread(job_state)
end

#idle?(duration = nil) ⇒ Boolean

Returns Whether the capsule is idle.

Parameters:

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

    Length of idleness to check for (in seconds).

Returns:

  • (Boolean)

    Whether the capsule is idle



90
91
92
93
94
95
96
97
98
99
100
# File 'lib/good_job/capsule.rb', line 90

def idle?(duration = nil)
  scheduler_stats = @multi_scheduler&.stats || {}
  is_idle = scheduler_stats.fetch(:active_execution_thread_count, 0).zero?

  if is_idle && duration
    active_at = scheduler_stats.fetch(:execution_at, nil) || @started_at
    active_at.nil? || (Time.current - active_at >= duration)
  else
    is_idle
  end
end

#lower_thread_priority=(value) ⇒ Object



116
117
118
119
# File 'lib/good_job/capsule.rb', line 116

def lower_thread_priority=(value)
  @lower_thread_priority = value
  @multi_scheduler&.lower_thread_priority = value
end

#process_idString

UUID for this capsule; to be used for inspection (not directly for locking jobs).

Returns:

  • (String)


112
113
114
# File 'lib/good_job/capsule.rb', line 112

def process_id
  @tracker.process_id
end

#restart(timeout: NONE) ⇒ void

This method returns an undefined value.

Shutdown and then start the capsule again.

Parameters:

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

    Seconds to wait for active threads.

Raises:

  • (ArgumentError)


71
72
73
74
75
76
# File 'lib/good_job/capsule.rb', line 71

def restart(timeout: NONE)
  raise ArgumentError, "Capsule#restart cannot be called with a timeout of nil" if timeout.nil?

  shutdown(timeout: timeout)
  start(force: true)
end

#running?Boolean

Returns Whether the capsule is currently running.

Returns:

  • (Boolean)

    Whether the capsule is currently running.



79
80
81
# File 'lib/good_job/capsule.rb', line 79

def running?
  @started_at.present?
end

#shutdown(timeout: NONE) ⇒ void

This method returns an undefined value.

Shut down the thread pool executors.

Parameters:

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

    Seconds to wait for active threads.

    • -1 will wait for all active threads to complete.

    • 0 will interrupt active threads.

    • N will wait at most N seconds and then interrupt active threads.

    • nil will trigger a shutdown but not wait for it to complete.



61
62
63
64
65
66
# File 'lib/good_job/capsule.rb', line 61

def shutdown(timeout: NONE)
  timeout = configuration.shutdown_timeout if timeout == NONE
  GoodJob._shutdown_all([@notifier, @poller, @multi_scheduler, @cron_manager].compact, after: [@shared_executor], timeout: timeout)
  @startable = false
  @started_at = nil
end

#shutdown?Boolean

Returns Whether the capsule has been shutdown.

Returns:

  • (Boolean)

    Whether the capsule has been shutdown.



84
85
86
# File 'lib/good_job/capsule.rb', line 84

def shutdown?
  [@notifier, @poller, @multi_scheduler, @cron_manager].compact.all?(&:shutdown?)
end

#start(force: false) ⇒ nil, Boolean

Start the capsule once. After a shutdown, #restart must be used to start again.

Returns:

  • (nil, Boolean)

    Whether the capsule was started.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/good_job/capsule.rb', line 34

def start(force: false)
  return unless startable?(force: force)

  @mutex.synchronize do
    return unless startable?(force: force)

    @notifier = GoodJob::Notifier.new(enable_listening: configuration.enable_listen_notify, capsule: self, executor: @shared_executor)
    @poller = GoodJob::Poller.new(poll_interval: configuration.poll_interval)
    @multi_scheduler = GoodJob::MultiScheduler.from_configuration(configuration, capsule: self, warm_cache_on_initialize: true).tap do |multischeduler|
      multischeduler.lower_thread_priority = @lower_thread_priority unless @lower_thread_priority.nil?
    end
    @notifier.recipients.push([@multi_scheduler, :create_thread])
    @poller.recipients.push(-> { @multi_scheduler.create_thread({ fanout: true }) })

    @cron_manager = GoodJob::CronManager.new(configuration.cron_entries, start_on_initialize: true, executor: @shared_executor) if configuration.enable_cron?
    @startable = false
    @started_at = Time.current
  end
end