Class: Delayed::Monitor

Inherits:
Object
  • Object
show all
Includes:
Runnable
Defined in:
lib/delayed/monitor.rb

Constant Summary collapse

METRICS =
%w(
  count
  future_count
  locked_count
  erroring_count
  failed_count
  max_lock_age
  max_age
  working_count
  workable_count
  alert_age_percent
).freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Runnable

#start

Constructor Details

#initializeMonitor

Returns a new instance of Monitor.



28
29
30
31
32
33
34
# File 'lib/delayed/monitor.rb', line 28

def initialize
  validate_tag_columns!
  @tag_columns = self.class.tag_columns
  @jobs = Job.group(:priority, :queue)
  @jobs = @jobs.where(queue: Worker.queues) if Worker.queues.any?
  @memo = {}
end

Class Method Details

.parse_utc_time(string) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/delayed/monitor.rb', line 59

def self.parse_utc_time(string)
  # Depending on Rails version & DB adapter, this will be either a String or a DateTime.
  # If it's a DateTime, and if connection is running with the `:local` time zone config,
  # then by default Rails incorrectly assumes it's in local time instead of UTC.
  # We use `strftime` to strip the encoded TZ info and re-parse it as UTC.
  #
  # Example:
  # - "2026-02-05 10:01:23"        -> DB-returned string
  # - "2026-02-05 10:01:23 -0600"  -> Rails-parsed DateTime with incorrect TZ
  # - "2026-02-05 10:01:23"        -> `strftime` output
  # - "2026-02-05 04:01:23 -0600"  -> Re-parsed as UTC and converted to local time
  string = string.strftime('%Y-%m-%d %H:%M:%S') if string.respond_to?(:strftime)

  ActiveSupport::TimeZone.new("UTC").parse(string)
end

.sql_now_in_utcObject



48
49
50
51
52
53
54
55
56
57
# File 'lib/delayed/monitor.rb', line 48

def self.sql_now_in_utc
  case ActiveRecord::Base.connection.adapter_name
  when 'PostgreSQL'
    "TIMEZONE('UTC', STATEMENT_TIMESTAMP())"
  when 'MySQL', 'Mysql2'
    "UTC_TIMESTAMP()"
  else
    "CURRENT_TIMESTAMP"
  end
end

.tag_columnsObject



20
21
22
# File 'lib/delayed/monitor.rb', line 20

def self.tag_columns
  @tag_columns ||= [].freeze
end

.tag_columns=(columns) ⇒ Object



24
25
26
# File 'lib/delayed/monitor.rb', line 24

def self.tag_columns=(columns)
  @tag_columns = columns.map(&:to_sym).freeze
end

Instance Method Details

#query_for(metric) ⇒ Object



44
45
46
# File 'lib/delayed/monitor.rb', line 44

def query_for(metric)
  send(:"#{metric}_grouped")
end

#run!Object



36
37
38
39
40
41
42
# File 'lib/delayed/monitor.rb', line 36

def run!
  @memo = {}
  ActiveSupport::Notifications.instrument('delayed.monitor.run', default_tags) do
    METRICS.each { |metric| emit_metric!(metric) }
  end
  interruptable_sleep(sleep_delay)
end