delayed 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5fac8946441b682c8df0e1365cd446cb7d507e3831f8155d692abe6ef1d52003
4
- data.tar.gz: 602f57430c6ac8b7c94bd248f270ffe768d65de07d50bc2e482bfed67fc1ca7c
3
+ metadata.gz: 2078916c01265f24d3f7bb05ef6bb752dae563413973d4efaf8622bb3c7a40bf
4
+ data.tar.gz: d388130dd48000d4148eeb5246e8975989b45e106d144fcbea7ffbc140fb0e4e
5
5
  SHA512:
6
- metadata.gz: 3d5a2383bd876172d81e9d0926d818afe6f989af71e4143c970daf0ea5149f63cad5ccf0029be97e59765b4ceae77dc555578a76fb955ed67f1caaaf92c71352
7
- data.tar.gz: 0f33ed115647bbacfdfe27e9db20e075c2b7374d7ee23e57bbe1a983dacfc7d1cbea6e295fb7d672203664f98d151035675e4fccb35eeb2b627dadab921f2a4d
6
+ metadata.gz: f624aabb72e24fb49b8f81e1bf90562a6dd62354f5145ea6ff693d08b13a4089ef03a17544cc26359d5ef0891fdc2e1bdd6d82e7fc683684cb6006aefd12f8d3
7
+ data.tar.gz: c1a3066fcd79c66b0b264467364a9640d0854fe5a08cd61a4ed305ba23c3998afb9297775a7d49a9a2761799dc9bf56497173e73f618ddee8a3991303d2cff0e
@@ -147,11 +147,11 @@ module Delayed
147
147
  end
148
148
 
149
149
  def max_age_grouped
150
- live_counts.transform_values { |j| time_ago(db_now(j), j.run_at) }
150
+ pending_counts.transform_values { |j| time_ago(db_now(j), j.run_at) }
151
151
  end
152
152
 
153
153
  def alert_age_percent_grouped
154
- live_counts.each_with_object({}) do |((priority, queue), j), metrics|
154
+ pending_counts.each_with_object({}) do |((priority, queue), j), metrics|
155
155
  max_age = time_ago(db_now(j), j.run_at)
156
156
  alert_age = Priority.new(priority).alert_age
157
157
  metrics[[priority, queue]] = [max_age / alert_age * 100, 100].min if alert_age
@@ -169,17 +169,15 @@ module Delayed
169
169
  end
170
170
 
171
171
  def oldest_workable_job_grouped
172
- live_counts.transform_values(&:run_at).compact
172
+ pending_counts.transform_values(&:run_at).compact
173
173
  end
174
174
 
175
175
  def live_counts
176
176
  @memo[:live_counts] ||= grouped_query(
177
177
  jobs.live,
178
- include_db_time: true,
179
178
  count: [:count, '*'],
180
179
  future_count: [:sum, case_when(Job.future_clause.to_sql)],
181
180
  erroring_count: [:sum, case_when(Job.erroring_clause.to_sql)],
182
- run_at: [:min, case_when(Job.pending_clause.to_sql, 'run_at')],
183
181
  )
184
182
  end
185
183
 
@@ -190,6 +188,7 @@ module Delayed
190
188
  claimed_count: [:sum, case_when(Job.claimed_clause.to_sql)],
191
189
  claimable_count: [:sum, case_when(Job.claimable_clause.to_sql)],
192
190
  locked_at: [:min, case_when(Job.claimed_clause.to_sql, 'locked_at')],
191
+ run_at: [:min, case_when(Job.claimable_clause.to_sql, 'run_at')],
193
192
  )
194
193
  end
195
194
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delayed
4
- VERSION = '3.0.0'
4
+ VERSION = '3.0.1'
5
5
  end
@@ -27,29 +27,26 @@ GroupAggregate (cost=...)
27
27
  SELECT SUM(count) AS count,
28
28
  SUM(future_count) AS future_count,
29
29
  SUM(erroring_count) AS erroring_count,
30
- MIN(run_at) AS run_at,
31
- TIMEZONE('UTC', STATEMENT_TIMESTAMP()) AS db_now_utc,
32
30
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
33
31
  queue AS queue
34
32
  FROM (SELECT \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\", COUNT(*) AS count,
35
33
  SUM(CASE WHEN \"delayed_jobs\".\"run_at\" > '2025-11-10 17:20:13' THEN 1 ELSE 0 END) AS future_count,
36
- SUM(CASE WHEN \"delayed_jobs\".\"attempts\" > 0 THEN 1 ELSE 0 END) AS erroring_count,
37
- MIN(CASE WHEN \"delayed_jobs\".\"run_at\" <= '2025-11-10 17:20:13' THEN run_at ELSE NULL END) AS run_at
34
+ SUM(CASE WHEN \"delayed_jobs\".\"attempts\" > 0 THEN 1 ELSE 0 END) AS erroring_count
38
35
  FROM \"delayed_jobs\"
39
36
  WHERE \"delayed_jobs\".\"failed_at\" IS NULL
40
37
  GROUP BY \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\") subquery
41
38
  GROUP BY CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END, \"queue\"
42
39
 
43
40
  GroupAggregate (cost=...)
44
- Output: sum(subquery.count), sum(subquery.future_count), sum(subquery.erroring_count), min(subquery.run_at), timezone('UTC'::text, statement_timestamp()), (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
41
+ Output: sum(subquery.count), sum(subquery.future_count), sum(subquery.erroring_count), (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
45
42
  Group Key: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
46
43
  -> Sort (cost=...)
47
- Output: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue, subquery.count, subquery.future_count, subquery.erroring_count, subquery.run_at
44
+ Output: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue, subquery.count, subquery.future_count, subquery.erroring_count
48
45
  Sort Key: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
49
46
  -> Subquery Scan on subquery (cost=...)
50
- Output: CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END, subquery.queue, subquery.count, subquery.future_count, subquery.erroring_count, subquery.run_at
47
+ Output: CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END, subquery.queue, subquery.count, subquery.future_count, subquery.erroring_count
51
48
  -> GroupAggregate (cost=...)
52
- Output: delayed_jobs.priority, delayed_jobs.queue, count(*), sum(CASE WHEN (delayed_jobs.run_at > '2025-11-10 17:20:13'::timestamp without time zone) THEN 1 ELSE 0 END), sum(CASE WHEN (delayed_jobs.attempts > 0) THEN 1 ELSE 0 END), min(CASE WHEN (delayed_jobs.run_at <= '2025-11-10 17:20:13'::timestamp without time zone) THEN delayed_jobs.run_at ELSE NULL::timestamp without time zone END)
49
+ Output: delayed_jobs.priority, delayed_jobs.queue, count(*), sum(CASE WHEN (delayed_jobs.run_at > '2025-11-10 17:20:13'::timestamp without time zone) THEN 1 ELSE 0 END), sum(CASE WHEN (delayed_jobs.attempts > 0) THEN 1 ELSE 0 END)
53
50
  Group Key: delayed_jobs.priority, delayed_jobs.queue
54
51
  -> Sort (cost=...)
55
52
  Output: delayed_jobs.priority, delayed_jobs.queue, delayed_jobs.run_at, delayed_jobs.attempts
@@ -65,13 +62,16 @@ GroupAggregate (cost=...)
65
62
  SELECT SUM(claimed_count) AS claimed_count,
66
63
  SUM(claimable_count) AS claimable_count,
67
64
  MIN(locked_at) AS locked_at,
65
+ MIN(run_at) AS run_at,
68
66
  TIMEZONE('UTC', STATEMENT_TIMESTAMP()) AS db_now_utc,
69
67
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
70
68
  queue AS queue
71
69
  FROM (SELECT \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\", SUM(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN 1 ELSE 0 END) AS claimed_count,
72
70
  SUM(CASE WHEN (\"delayed_jobs\".\"locked_at\" IS NULL
73
71
  OR \"delayed_jobs\".\"locked_at\" < '2025-11-10 16:59:43') THEN 1 ELSE 0 END) AS claimable_count,
74
- MIN(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at
72
+ MIN(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at,
73
+ MIN(CASE WHEN (\"delayed_jobs\".\"locked_at\" IS NULL
74
+ OR \"delayed_jobs\".\"locked_at\" < '2025-11-10 16:59:43') THEN run_at ELSE NULL END) AS run_at
75
75
  FROM \"delayed_jobs\"
76
76
  WHERE \"delayed_jobs\".\"failed_at\" IS NULL
77
77
  AND \"delayed_jobs\".\"run_at\" <= '2025-11-10 17:20:13'
@@ -79,21 +79,21 @@ SELECT SUM(claimed_count) AS claimed_count,
79
79
  GROUP BY CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END, \"queue\"
80
80
 
81
81
  GroupAggregate (cost=...)
82
- Output: sum(subquery.claimed_count), sum(subquery.claimable_count), min(subquery.locked_at), timezone('UTC'::text, statement_timestamp()), (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
82
+ Output: sum(subquery.claimed_count), sum(subquery.claimable_count), min(subquery.locked_at), min(subquery.run_at), timezone('UTC'::text, statement_timestamp()), (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
83
83
  Group Key: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
84
84
  -> Sort (cost=...)
85
- Output: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue, subquery.claimed_count, subquery.claimable_count, subquery.locked_at
85
+ Output: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue, subquery.claimed_count, subquery.claimable_count, subquery.locked_at, subquery.run_at
86
86
  Sort Key: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
87
87
  -> Subquery Scan on subquery (cost=...)
88
- Output: CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END, subquery.queue, subquery.claimed_count, subquery.claimable_count, subquery.locked_at
88
+ Output: CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END, subquery.queue, subquery.claimed_count, subquery.claimable_count, subquery.locked_at, subquery.run_at
89
89
  -> GroupAggregate (cost=...)
90
- Output: delayed_jobs.priority, delayed_jobs.queue, sum(CASE WHEN (delayed_jobs.locked_at >= '2025-11-10 16:59:43'::timestamp without time zone) THEN 1 ELSE 0 END), sum(CASE WHEN ((delayed_jobs.locked_at IS NULL) OR (delayed_jobs.locked_at < '2025-11-10 16:59:43'::timestamp without time zone)) THEN 1 ELSE 0 END), min(CASE WHEN (delayed_jobs.locked_at >= '2025-11-10 16:59:43'::timestamp without time zone) THEN delayed_jobs.locked_at ELSE NULL::timestamp without time zone END)
90
+ Output: delayed_jobs.priority, delayed_jobs.queue, sum(CASE WHEN (delayed_jobs.locked_at >= '2025-11-10 16:59:43'::timestamp without time zone) THEN 1 ELSE 0 END), sum(CASE WHEN ((delayed_jobs.locked_at IS NULL) OR (delayed_jobs.locked_at < '2025-11-10 16:59:43'::timestamp without time zone)) THEN 1 ELSE 0 END), min(CASE WHEN (delayed_jobs.locked_at >= '2025-11-10 16:59:43'::timestamp without time zone) THEN delayed_jobs.locked_at ELSE NULL::timestamp without time zone END), min(CASE WHEN ((delayed_jobs.locked_at IS NULL) OR (delayed_jobs.locked_at < '2025-11-10 16:59:43'::timestamp without time zone)) THEN delayed_jobs.run_at ELSE NULL::timestamp without time zone END)
91
91
  Group Key: delayed_jobs.priority, delayed_jobs.queue
92
92
  -> Sort (cost=...)
93
- Output: delayed_jobs.priority, delayed_jobs.queue, delayed_jobs.locked_at
93
+ Output: delayed_jobs.priority, delayed_jobs.queue, delayed_jobs.locked_at, delayed_jobs.run_at
94
94
  Sort Key: delayed_jobs.priority, delayed_jobs.queue
95
95
  -> Index Scan using idx_delayed_jobs_live on public.delayed_jobs (cost=...)
96
- Output: delayed_jobs.priority, delayed_jobs.queue, delayed_jobs.locked_at
96
+ Output: delayed_jobs.priority, delayed_jobs.queue, delayed_jobs.locked_at, delayed_jobs.run_at
97
97
  Index Cond: (delayed_jobs.run_at <= '2025-11-10 17:20:13'::timestamp without time zone)
98
98
  ---
99
99
  -- QUERIES FOR `erroring_count`:
@@ -152,29 +152,26 @@ GroupAggregate (cost=...)
152
152
  SELECT SUM(count) AS count,
153
153
  SUM(future_count) AS future_count,
154
154
  SUM(erroring_count) AS erroring_count,
155
- MIN(run_at) AS run_at,
156
- TIMEZONE('UTC', STATEMENT_TIMESTAMP()) AS db_now_utc,
157
155
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
158
156
  queue AS queue
159
157
  FROM (SELECT \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\", COUNT(*) AS count,
160
158
  SUM(CASE WHEN \"delayed_jobs\".\"run_at\" > '2025-11-10 17:20:13' THEN 1 ELSE 0 END) AS future_count,
161
- SUM(CASE WHEN \"delayed_jobs\".\"attempts\" > 0 THEN 1 ELSE 0 END) AS erroring_count,
162
- MIN(CASE WHEN \"delayed_jobs\".\"run_at\" <= '2025-11-10 17:20:13' THEN run_at ELSE NULL END) AS run_at
159
+ SUM(CASE WHEN \"delayed_jobs\".\"attempts\" > 0 THEN 1 ELSE 0 END) AS erroring_count
163
160
  FROM \"delayed_jobs\"
164
161
  WHERE \"delayed_jobs\".\"failed_at\" IS NULL
165
162
  GROUP BY \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\") subquery
166
163
  GROUP BY CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END, \"queue\"
167
164
 
168
165
  GroupAggregate (cost=...)
169
- Output: sum(subquery.count), sum(subquery.future_count), sum(subquery.erroring_count), min(subquery.run_at), timezone('UTC'::text, statement_timestamp()), (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
166
+ Output: sum(subquery.count), sum(subquery.future_count), sum(subquery.erroring_count), (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
170
167
  Group Key: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
171
168
  -> Sort (cost=...)
172
- Output: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue, subquery.count, subquery.future_count, subquery.erroring_count, subquery.run_at
169
+ Output: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue, subquery.count, subquery.future_count, subquery.erroring_count
173
170
  Sort Key: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
174
171
  -> Subquery Scan on subquery (cost=...)
175
- Output: CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END, subquery.queue, subquery.count, subquery.future_count, subquery.erroring_count, subquery.run_at
172
+ Output: CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END, subquery.queue, subquery.count, subquery.future_count, subquery.erroring_count
176
173
  -> GroupAggregate (cost=...)
177
- Output: delayed_jobs.priority, delayed_jobs.queue, count(*), sum(CASE WHEN (delayed_jobs.run_at > '2025-11-10 17:20:13'::timestamp without time zone) THEN 1 ELSE 0 END), sum(CASE WHEN (delayed_jobs.attempts > 0) THEN 1 ELSE 0 END), min(CASE WHEN (delayed_jobs.run_at <= '2025-11-10 17:20:13'::timestamp without time zone) THEN delayed_jobs.run_at ELSE NULL::timestamp without time zone END)
174
+ Output: delayed_jobs.priority, delayed_jobs.queue, count(*), sum(CASE WHEN (delayed_jobs.run_at > '2025-11-10 17:20:13'::timestamp without time zone) THEN 1 ELSE 0 END), sum(CASE WHEN (delayed_jobs.attempts > 0) THEN 1 ELSE 0 END)
178
175
  Group Key: delayed_jobs.priority, delayed_jobs.queue
179
176
  -> Sort (cost=...)
180
177
  Output: delayed_jobs.priority, delayed_jobs.queue, delayed_jobs.run_at, delayed_jobs.attempts
@@ -191,13 +188,16 @@ GroupAggregate (cost=...)
191
188
  SELECT SUM(claimed_count) AS claimed_count,
192
189
  SUM(claimable_count) AS claimable_count,
193
190
  MIN(locked_at) AS locked_at,
191
+ MIN(run_at) AS run_at,
194
192
  TIMEZONE('UTC', STATEMENT_TIMESTAMP()) AS db_now_utc,
195
193
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
196
194
  queue AS queue
197
195
  FROM (SELECT \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\", SUM(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN 1 ELSE 0 END) AS claimed_count,
198
196
  SUM(CASE WHEN (\"delayed_jobs\".\"locked_at\" IS NULL
199
197
  OR \"delayed_jobs\".\"locked_at\" < '2025-11-10 16:59:43') THEN 1 ELSE 0 END) AS claimable_count,
200
- MIN(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at
198
+ MIN(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at,
199
+ MIN(CASE WHEN (\"delayed_jobs\".\"locked_at\" IS NULL
200
+ OR \"delayed_jobs\".\"locked_at\" < '2025-11-10 16:59:43') THEN run_at ELSE NULL END) AS run_at
201
201
  FROM \"delayed_jobs\"
202
202
  WHERE \"delayed_jobs\".\"failed_at\" IS NULL
203
203
  AND \"delayed_jobs\".\"run_at\" <= '2025-11-10 17:20:13'
@@ -205,21 +205,21 @@ SELECT SUM(claimed_count) AS claimed_count,
205
205
  GROUP BY CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END, \"queue\"
206
206
 
207
207
  GroupAggregate (cost=...)
208
- Output: sum(subquery.claimed_count), sum(subquery.claimable_count), min(subquery.locked_at), timezone('UTC'::text, statement_timestamp()), (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
208
+ Output: sum(subquery.claimed_count), sum(subquery.claimable_count), min(subquery.locked_at), min(subquery.run_at), timezone('UTC'::text, statement_timestamp()), (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
209
209
  Group Key: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
210
210
  -> Sort (cost=...)
211
- Output: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue, subquery.claimed_count, subquery.claimable_count, subquery.locked_at
211
+ Output: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue, subquery.claimed_count, subquery.claimable_count, subquery.locked_at, subquery.run_at
212
212
  Sort Key: (CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END), subquery.queue
213
213
  -> Subquery Scan on subquery (cost=...)
214
- Output: CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END, subquery.queue, subquery.claimed_count, subquery.claimable_count, subquery.locked_at
214
+ Output: CASE WHEN (subquery.priority < 10) THEN 0 WHEN (subquery.priority < 20) THEN 10 WHEN (subquery.priority < 30) THEN 20 WHEN (subquery.priority >= 30) THEN 30 ELSE NULL::integer END, subquery.queue, subquery.claimed_count, subquery.claimable_count, subquery.locked_at, subquery.run_at
215
215
  -> GroupAggregate (cost=...)
216
- Output: delayed_jobs.priority, delayed_jobs.queue, sum(CASE WHEN (delayed_jobs.locked_at >= '2025-11-10 16:59:43'::timestamp without time zone) THEN 1 ELSE 0 END), sum(CASE WHEN ((delayed_jobs.locked_at IS NULL) OR (delayed_jobs.locked_at < '2025-11-10 16:59:43'::timestamp without time zone)) THEN 1 ELSE 0 END), min(CASE WHEN (delayed_jobs.locked_at >= '2025-11-10 16:59:43'::timestamp without time zone) THEN delayed_jobs.locked_at ELSE NULL::timestamp without time zone END)
216
+ Output: delayed_jobs.priority, delayed_jobs.queue, sum(CASE WHEN (delayed_jobs.locked_at >= '2025-11-10 16:59:43'::timestamp without time zone) THEN 1 ELSE 0 END), sum(CASE WHEN ((delayed_jobs.locked_at IS NULL) OR (delayed_jobs.locked_at < '2025-11-10 16:59:43'::timestamp without time zone)) THEN 1 ELSE 0 END), min(CASE WHEN (delayed_jobs.locked_at >= '2025-11-10 16:59:43'::timestamp without time zone) THEN delayed_jobs.locked_at ELSE NULL::timestamp without time zone END), min(CASE WHEN ((delayed_jobs.locked_at IS NULL) OR (delayed_jobs.locked_at < '2025-11-10 16:59:43'::timestamp without time zone)) THEN delayed_jobs.run_at ELSE NULL::timestamp without time zone END)
217
217
  Group Key: delayed_jobs.priority, delayed_jobs.queue
218
218
  -> Sort (cost=...)
219
- Output: delayed_jobs.priority, delayed_jobs.queue, delayed_jobs.locked_at
219
+ Output: delayed_jobs.priority, delayed_jobs.queue, delayed_jobs.locked_at, delayed_jobs.run_at
220
220
  Sort Key: delayed_jobs.priority, delayed_jobs.queue
221
221
  -> Index Scan using delayed_jobs_priority on public.delayed_jobs (cost=...)
222
- Output: delayed_jobs.priority, delayed_jobs.queue, delayed_jobs.locked_at
222
+ Output: delayed_jobs.priority, delayed_jobs.queue, delayed_jobs.locked_at, delayed_jobs.run_at
223
223
  Index Cond: (delayed_jobs.run_at <= '2025-11-10 17:20:13'::timestamp without time zone)
224
224
  Filter: (delayed_jobs.failed_at IS NULL)
225
225
  ---
@@ -266,14 +266,11 @@ USE TEMP B-TREE FOR GROUP BY
266
266
  SELECT SUM(count) AS count,
267
267
  SUM(future_count) AS future_count,
268
268
  SUM(erroring_count) AS erroring_count,
269
- MIN(run_at) AS run_at,
270
- CURRENT_TIMESTAMP AS db_now_utc,
271
269
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
272
270
  queue AS queue
273
271
  FROM (SELECT \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\", COUNT(*) AS count,
274
272
  SUM(CASE WHEN \"delayed_jobs\".\"run_at\" > '2025-11-10 17:20:13' THEN 1 ELSE 0 END) AS future_count,
275
- SUM(CASE WHEN \"delayed_jobs\".\"attempts\" > 0 THEN 1 ELSE 0 END) AS erroring_count,
276
- MIN(CASE WHEN \"delayed_jobs\".\"run_at\" <= '2025-11-10 17:20:13' THEN run_at ELSE NULL END) AS run_at
273
+ SUM(CASE WHEN \"delayed_jobs\".\"attempts\" > 0 THEN 1 ELSE 0 END) AS erroring_count
277
274
  FROM \"delayed_jobs\"
278
275
  WHERE \"delayed_jobs\".\"failed_at\" IS NULL
279
276
  GROUP BY \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\") subquery
@@ -293,13 +290,16 @@ USE TEMP B-TREE FOR GROUP BY
293
290
  SELECT SUM(claimed_count) AS claimed_count,
294
291
  SUM(claimable_count) AS claimable_count,
295
292
  MIN(locked_at) AS locked_at,
293
+ MIN(run_at) AS run_at,
296
294
  CURRENT_TIMESTAMP AS db_now_utc,
297
295
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
298
296
  queue AS queue
299
297
  FROM (SELECT \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\", SUM(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN 1 ELSE 0 END) AS claimed_count,
300
298
  SUM(CASE WHEN (\"delayed_jobs\".\"locked_at\" IS NULL
301
299
  OR \"delayed_jobs\".\"locked_at\" < '2025-11-10 16:59:43') THEN 1 ELSE 0 END) AS claimable_count,
302
- MIN(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at
300
+ MIN(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at,
301
+ MIN(CASE WHEN (\"delayed_jobs\".\"locked_at\" IS NULL
302
+ OR \"delayed_jobs\".\"locked_at\" < '2025-11-10 16:59:43') THEN run_at ELSE NULL END) AS run_at
303
303
  FROM \"delayed_jobs\"
304
304
  WHERE \"delayed_jobs\".\"failed_at\" IS NULL
305
305
  AND \"delayed_jobs\".\"run_at\" <= '2025-11-10 17:20:13'
@@ -356,14 +356,11 @@ USE TEMP B-TREE FOR GROUP BY
356
356
  SELECT SUM(count) AS count,
357
357
  SUM(future_count) AS future_count,
358
358
  SUM(erroring_count) AS erroring_count,
359
- MIN(run_at) AS run_at,
360
- CURRENT_TIMESTAMP AS db_now_utc,
361
359
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
362
360
  queue AS queue
363
361
  FROM (SELECT \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\", COUNT(*) AS count,
364
362
  SUM(CASE WHEN \"delayed_jobs\".\"run_at\" > '2025-11-10 17:20:13' THEN 1 ELSE 0 END) AS future_count,
365
- SUM(CASE WHEN \"delayed_jobs\".\"attempts\" > 0 THEN 1 ELSE 0 END) AS erroring_count,
366
- MIN(CASE WHEN \"delayed_jobs\".\"run_at\" <= '2025-11-10 17:20:13' THEN run_at ELSE NULL END) AS run_at
363
+ SUM(CASE WHEN \"delayed_jobs\".\"attempts\" > 0 THEN 1 ELSE 0 END) AS erroring_count
367
364
  FROM \"delayed_jobs\"
368
365
  WHERE \"delayed_jobs\".\"failed_at\" IS NULL
369
366
  GROUP BY \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\") subquery
@@ -383,13 +380,16 @@ USE TEMP B-TREE FOR GROUP BY
383
380
  SELECT SUM(claimed_count) AS claimed_count,
384
381
  SUM(claimable_count) AS claimable_count,
385
382
  MIN(locked_at) AS locked_at,
383
+ MIN(run_at) AS run_at,
386
384
  CURRENT_TIMESTAMP AS db_now_utc,
387
385
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
388
386
  queue AS queue
389
387
  FROM (SELECT \"delayed_jobs\".\"priority\", \"delayed_jobs\".\"queue\", SUM(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN 1 ELSE 0 END) AS claimed_count,
390
388
  SUM(CASE WHEN (\"delayed_jobs\".\"locked_at\" IS NULL
391
389
  OR \"delayed_jobs\".\"locked_at\" < '2025-11-10 16:59:43') THEN 1 ELSE 0 END) AS claimable_count,
392
- MIN(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at
390
+ MIN(CASE WHEN \"delayed_jobs\".\"locked_at\" >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at,
391
+ MIN(CASE WHEN (\"delayed_jobs\".\"locked_at\" IS NULL
392
+ OR \"delayed_jobs\".\"locked_at\" < '2025-11-10 16:59:43') THEN run_at ELSE NULL END) AS run_at
393
393
  FROM \"delayed_jobs\"
394
394
  WHERE \"delayed_jobs\".\"failed_at\" IS NULL
395
395
  AND \"delayed_jobs\".\"run_at\" <= '2025-11-10 17:20:13'
@@ -449,14 +449,11 @@ SELECT SUM(count) AS count,
449
449
  SELECT SUM(count) AS count,
450
450
  SUM(future_count) AS future_count,
451
451
  SUM(erroring_count) AS erroring_count,
452
- MIN(run_at) AS run_at,
453
- UTC_TIMESTAMP() AS db_now_utc,
454
452
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
455
453
  queue AS queue
456
454
  FROM (SELECT `delayed_jobs`.`priority`, `delayed_jobs`.`queue`, COUNT(*) AS count,
457
455
  SUM(CASE WHEN `delayed_jobs`.`run_at` > '2025-11-10 17:20:13' THEN 1 ELSE 0 END) AS future_count,
458
- SUM(CASE WHEN `delayed_jobs`.`attempts` > 0 THEN 1 ELSE 0 END) AS erroring_count,
459
- MIN(CASE WHEN `delayed_jobs`.`run_at` <= '2025-11-10 17:20:13' THEN run_at ELSE NULL END) AS run_at
456
+ SUM(CASE WHEN `delayed_jobs`.`attempts` > 0 THEN 1 ELSE 0 END) AS erroring_count
460
457
  FROM `delayed_jobs`
461
458
  WHERE `delayed_jobs`.`failed_at` IS NULL
462
459
  GROUP BY `delayed_jobs`.`priority`, `delayed_jobs`.`queue`) subquery
@@ -479,13 +476,16 @@ SELECT SUM(count) AS count,
479
476
  SELECT SUM(claimed_count) AS claimed_count,
480
477
  SUM(claimable_count) AS claimable_count,
481
478
  MIN(locked_at) AS locked_at,
479
+ MIN(run_at) AS run_at,
482
480
  UTC_TIMESTAMP() AS db_now_utc,
483
481
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
484
482
  queue AS queue
485
483
  FROM (SELECT `delayed_jobs`.`priority`, `delayed_jobs`.`queue`, SUM(CASE WHEN `delayed_jobs`.`locked_at` >= '2025-11-10 16:59:43' THEN 1 ELSE 0 END) AS claimed_count,
486
484
  SUM(CASE WHEN (`delayed_jobs`.`locked_at` IS NULL
487
485
  OR `delayed_jobs`.`locked_at` < '2025-11-10 16:59:43') THEN 1 ELSE 0 END) AS claimable_count,
488
- MIN(CASE WHEN `delayed_jobs`.`locked_at` >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at
486
+ MIN(CASE WHEN `delayed_jobs`.`locked_at` >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at,
487
+ MIN(CASE WHEN (`delayed_jobs`.`locked_at` IS NULL
488
+ OR `delayed_jobs`.`locked_at` < '2025-11-10 16:59:43') THEN run_at ELSE NULL END) AS run_at
489
489
  FROM `delayed_jobs`
490
490
  WHERE `delayed_jobs`.`failed_at` IS NULL
491
491
  AND `delayed_jobs`.`run_at` <= '2025-11-10 17:20:13'
@@ -548,14 +548,11 @@ SELECT SUM(count) AS count,
548
548
  SELECT SUM(count) AS count,
549
549
  SUM(future_count) AS future_count,
550
550
  SUM(erroring_count) AS erroring_count,
551
- MIN(run_at) AS run_at,
552
- UTC_TIMESTAMP() AS db_now_utc,
553
551
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
554
552
  queue AS queue
555
553
  FROM (SELECT `delayed_jobs`.`priority`, `delayed_jobs`.`queue`, COUNT(*) AS count,
556
554
  SUM(CASE WHEN `delayed_jobs`.`run_at` > '2025-11-10 17:20:13' THEN 1 ELSE 0 END) AS future_count,
557
- SUM(CASE WHEN `delayed_jobs`.`attempts` > 0 THEN 1 ELSE 0 END) AS erroring_count,
558
- MIN(CASE WHEN `delayed_jobs`.`run_at` <= '2025-11-10 17:20:13' THEN run_at ELSE NULL END) AS run_at
555
+ SUM(CASE WHEN `delayed_jobs`.`attempts` > 0 THEN 1 ELSE 0 END) AS erroring_count
559
556
  FROM `delayed_jobs`
560
557
  WHERE `delayed_jobs`.`failed_at` IS NULL
561
558
  GROUP BY `delayed_jobs`.`priority`, `delayed_jobs`.`queue`) subquery
@@ -578,13 +575,16 @@ SELECT SUM(count) AS count,
578
575
  SELECT SUM(claimed_count) AS claimed_count,
579
576
  SUM(claimable_count) AS claimable_count,
580
577
  MIN(locked_at) AS locked_at,
578
+ MIN(run_at) AS run_at,
581
579
  UTC_TIMESTAMP() AS db_now_utc,
582
580
  CASE WHEN priority < 10 THEN 0 WHEN priority < 20 THEN 10 WHEN priority < 30 THEN 20 WHEN priority >= 30 THEN 30 END AS priority,
583
581
  queue AS queue
584
582
  FROM (SELECT `delayed_jobs`.`priority`, `delayed_jobs`.`queue`, SUM(CASE WHEN `delayed_jobs`.`locked_at` >= '2025-11-10 16:59:43' THEN 1 ELSE 0 END) AS claimed_count,
585
583
  SUM(CASE WHEN (`delayed_jobs`.`locked_at` IS NULL
586
584
  OR `delayed_jobs`.`locked_at` < '2025-11-10 16:59:43') THEN 1 ELSE 0 END) AS claimable_count,
587
- MIN(CASE WHEN `delayed_jobs`.`locked_at` >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at
585
+ MIN(CASE WHEN `delayed_jobs`.`locked_at` >= '2025-11-10 16:59:43' THEN locked_at ELSE NULL END) AS locked_at,
586
+ MIN(CASE WHEN (`delayed_jobs`.`locked_at` IS NULL
587
+ OR `delayed_jobs`.`locked_at` < '2025-11-10 16:59:43') THEN run_at ELSE NULL END) AS run_at
588
588
  FROM `delayed_jobs`
589
589
  WHERE `delayed_jobs`.`failed_at` IS NULL
590
590
  AND `delayed_jobs`.`run_at` <= '2025-11-10 17:20:13'
@@ -344,6 +344,44 @@ RSpec.describe Delayed::Monitor do
344
344
  end
345
345
  end
346
346
  end
347
+
348
+ context 'when a job is locked (in-flight)' do
349
+ let(:payload) { default_payload.merge(priority: 'interactive') }
350
+ let(:base_attributes) do
351
+ {
352
+ priority: 0,
353
+ queue: 'default',
354
+ handler: "--- !ruby/object:SimpleJob\n",
355
+ name: 'SimpleJob',
356
+ attempts: 0,
357
+ }
358
+ end
359
+
360
+ # A single slow, in-flight job: old run_at, but currently locked by a worker.
361
+ let!(:locked_job) { Delayed::Job.create! base_attributes.merge(run_at: now - 1.hour, locked_at: now - 5.minutes) }
362
+
363
+ it 'excludes the locked job from max_age and alert_age_percent' do
364
+ expect { subject.run! }
365
+ .to emit_notification("delayed.job.locked_count").with_payload(payload).with_value(1)
366
+ .and emit_notification("delayed.job.workable_count").with_payload(payload).with_value(0)
367
+ .and emit_notification("delayed.job.max_lock_age").with_payload(payload).approximately.with_value(5.minutes)
368
+ .and emit_notification("delayed.job.max_age").with_payload(payload).approximately.with_value(0)
369
+ .and emit_notification("delayed.job.alert_age_percent").with_payload(payload).approximately.with_value(0)
370
+ end
371
+
372
+ context 'and a workable job is also present in the same group' do
373
+ # The workable job's run_at is newer than the locked job's, so max_age must
374
+ # track the workable job (30s), not the locked job (1 hour).
375
+ let!(:workable_job) { Delayed::Job.create! base_attributes.merge(run_at: now - 30.seconds) }
376
+
377
+ it 'reports max_age from the workable job only' do
378
+ expect { subject.run! }
379
+ .to emit_notification("delayed.job.locked_count").with_payload(payload).with_value(1)
380
+ .and emit_notification("delayed.job.workable_count").with_payload(payload).with_value(1)
381
+ .and emit_notification("delayed.job.max_age").with_payload(payload).approximately.with_value(30.seconds)
382
+ end
383
+ end
384
+ end
347
385
  end
348
386
 
349
387
  describe 'SQL' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Griffith
@@ -19,7 +19,7 @@ authors:
19
19
  autorequire:
20
20
  bindir: bin
21
21
  cert_chain: []
22
- date: 2026-06-08 00:00:00.000000000 Z
22
+ date: 2026-06-15 00:00:00.000000000 Z
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
25
25
  name: activerecord