delayed 2.0.3 → 2.2.0
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 +4 -4
- data/app/models/delayed/job.rb +26 -10
- data/lib/delayed/backend/job_preparer.rb +13 -0
- data/lib/delayed/exceptions.rb +2 -0
- data/lib/delayed/monitor.rb +103 -30
- data/lib/delayed/tasks.rb +31 -11
- data/lib/delayed/version.rb +1 -1
- data/lib/delayed/worker.rb +2 -0
- data/spec/delayed/__snapshots__/monitor_spec.rb.snap +447 -1170
- data/spec/delayed/job_spec.rb +37 -6
- data/spec/delayed/monitor_spec.rb +309 -240
- data/spec/helper.rb +24 -13
- metadata +2 -2
|
@@ -14,267 +14,338 @@ RSpec.describe Delayed::Monitor do
|
|
|
14
14
|
}
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
.to emit_notification("delayed.monitor.run").with_payload(default_payload.except(:queue))
|
|
20
|
-
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
21
|
-
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
22
|
-
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
23
|
-
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
24
|
-
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
25
|
-
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
26
|
-
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
27
|
-
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
28
|
-
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
29
|
-
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
30
|
-
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
31
|
-
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
32
|
-
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
33
|
-
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
34
|
-
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
35
|
-
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
36
|
-
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
37
|
-
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
38
|
-
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
39
|
-
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
40
|
-
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
41
|
-
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
42
|
-
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
43
|
-
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
44
|
-
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
45
|
-
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
46
|
-
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
47
|
-
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
48
|
-
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
49
|
-
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
50
|
-
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
51
|
-
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
52
|
-
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
53
|
-
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
54
|
-
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
55
|
-
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
56
|
-
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
57
|
-
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
58
|
-
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
59
|
-
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
60
|
-
end
|
|
17
|
+
describe '#run!' do
|
|
18
|
+
let(:app_local_db_time) { false }
|
|
61
19
|
|
|
62
|
-
context 'when named priorities are customized' do
|
|
63
20
|
around do |example|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it 'emits empty metrics for all custom priorities' do
|
|
71
|
-
expect { subject.run! }
|
|
72
|
-
.to emit_notification("delayed.monitor.run").with_payload(default_payload.except(:queue))
|
|
73
|
-
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
74
|
-
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
75
|
-
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
76
|
-
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
77
|
-
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
78
|
-
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
79
|
-
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
80
|
-
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
81
|
-
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
82
|
-
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
83
|
-
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
84
|
-
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
85
|
-
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
86
|
-
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
87
|
-
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
88
|
-
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
89
|
-
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
90
|
-
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
91
|
-
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
92
|
-
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
21
|
+
if app_local_db_time
|
|
22
|
+
Time.zone = 'US/Central'
|
|
23
|
+
self.default_timezone = :local
|
|
24
|
+
end
|
|
95
25
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
26
|
+
# On PostgreSQL, running examples in a transaction allows CURRENT_TIMESTAMP to remain stable.
|
|
27
|
+
# We can in turn use this to set Timecop to the same time as the DB for deterministic time math.
|
|
28
|
+
Delayed::Job.transaction do
|
|
29
|
+
now = described_class.parse_utc_time(
|
|
30
|
+
Delayed::Job.connection.select_value("SELECT #{described_class.sql_now_in_utc}"),
|
|
31
|
+
)
|
|
32
|
+
Timecop.freeze(now) { example.run }
|
|
33
|
+
end
|
|
34
|
+
ensure
|
|
35
|
+
Time.zone = nil
|
|
36
|
+
self.default_timezone = :utc
|
|
105
37
|
end
|
|
106
|
-
let(:failed_attributes) { { run_at: now - 1.week, attempts: 1, failed_at: now - 1.day, locked_at: now - 1.day } }
|
|
107
|
-
let(:p0_attributes) { job_attributes.merge(priority: 1, attempts: 1) }
|
|
108
|
-
let(:p10_attributes) { job_attributes.merge(priority: 13, locked_at: now - 1.day) }
|
|
109
|
-
let(:p20_attributes) { job_attributes.merge(priority: 23, attempts: 1) }
|
|
110
|
-
let(:p30_attributes) { job_attributes.merge(priority: 999, locked_at: now - 1.day) }
|
|
111
|
-
let(:p0_payload) { default_payload.merge(priority: 'interactive') }
|
|
112
|
-
let(:p10_payload) { default_payload.merge(priority: 'user_visible') }
|
|
113
|
-
let(:p20_payload) { default_payload.merge(priority: 'eventual') }
|
|
114
|
-
let(:p30_payload) { default_payload.merge(priority: 'reporting') }
|
|
115
|
-
let!(:p0_workable_job) { Delayed::Job.create! p0_attributes.merge(run_at: now - 30.seconds) }
|
|
116
|
-
let!(:p0_failed_job) { Delayed::Job.create! p0_attributes.merge(failed_attributes) }
|
|
117
|
-
let!(:p0_future_job) { Delayed::Job.create! p0_attributes.merge(run_at: now + 1.hour) }
|
|
118
|
-
let!(:p0_working_job) { Delayed::Job.create! p0_attributes.merge(locked_at: now - 3.minutes) }
|
|
119
|
-
let!(:p10_workable_job) { Delayed::Job.create! p10_attributes.merge(run_at: now - 2.minutes) }
|
|
120
|
-
let!(:p10_failed_job) { Delayed::Job.create! p10_attributes.merge(failed_attributes) }
|
|
121
|
-
let!(:p10_future_job) { Delayed::Job.create! p10_attributes.merge(run_at: now + 1.hour) }
|
|
122
|
-
let!(:p10_working_job) { Delayed::Job.create! p10_attributes.merge(locked_at: now - 7.minutes) }
|
|
123
|
-
let!(:p20_workable_job) { Delayed::Job.create! p20_attributes.merge(run_at: now - 1.hour) }
|
|
124
|
-
let!(:p20_failed_job) { Delayed::Job.create! p20_attributes.merge(failed_attributes) }
|
|
125
|
-
let!(:p20_future_job) { Delayed::Job.create! p20_attributes.merge(run_at: now + 1.hour) }
|
|
126
|
-
let!(:p20_working_job) { Delayed::Job.create! p20_attributes.merge(locked_at: now - 9.minutes) }
|
|
127
|
-
let!(:p30_workable_job) { Delayed::Job.create! p30_attributes.merge(run_at: now - 6.hours) }
|
|
128
|
-
let!(:p30_failed_job) { Delayed::Job.create! p30_attributes.merge(failed_attributes) }
|
|
129
|
-
let!(:p30_future_job) { Delayed::Job.create! p30_attributes.merge(run_at: now + 1.hour) }
|
|
130
|
-
let!(:p30_working_job) { Delayed::Job.create! p30_attributes.merge(locked_at: now - 11.minutes) }
|
|
131
|
-
let!(:p30_workable_job_in_other_queue) { Delayed::Job.create! p30_attributes.merge(run_at: now - 4.hours, queue: 'banana') }
|
|
132
38
|
|
|
133
|
-
|
|
134
|
-
Timecop.freeze(now) { example.run }
|
|
135
|
-
end
|
|
39
|
+
let(:now) { Delayed::Job.db_time_now }
|
|
136
40
|
|
|
137
|
-
it 'emits
|
|
41
|
+
it 'emits empty metrics for all default priorities' do
|
|
138
42
|
expect { subject.run! }
|
|
139
43
|
.to emit_notification("delayed.monitor.run").with_payload(default_payload.except(:queue))
|
|
140
|
-
.and emit_notification("delayed.job.count").with_payload(
|
|
141
|
-
.and emit_notification("delayed.job.
|
|
142
|
-
.and emit_notification("delayed.job.
|
|
143
|
-
.and emit_notification("delayed.job.
|
|
144
|
-
.and emit_notification("delayed.job.
|
|
145
|
-
.and emit_notification("delayed.job.
|
|
146
|
-
.and emit_notification("delayed.job.
|
|
147
|
-
.and emit_notification("delayed.job.
|
|
148
|
-
.and emit_notification("delayed.job.
|
|
149
|
-
.and emit_notification("delayed.job.
|
|
150
|
-
.and emit_notification("delayed.job.
|
|
151
|
-
.and emit_notification("delayed.job.
|
|
152
|
-
.and emit_notification("delayed.job.
|
|
153
|
-
.and emit_notification("delayed.job.erroring_count").with_payload(
|
|
154
|
-
.and emit_notification("delayed.job.
|
|
155
|
-
.and emit_notification("delayed.job.
|
|
156
|
-
.and emit_notification("delayed.job.
|
|
157
|
-
.and emit_notification("delayed.job.
|
|
158
|
-
.and emit_notification("delayed.job.
|
|
159
|
-
.and emit_notification("delayed.job.
|
|
160
|
-
.and emit_notification("delayed.job.
|
|
161
|
-
.and emit_notification("delayed.job.
|
|
162
|
-
.and emit_notification("delayed.job.
|
|
163
|
-
.and emit_notification("delayed.job.
|
|
164
|
-
.and emit_notification("delayed.job.
|
|
165
|
-
.and emit_notification("delayed.job.
|
|
166
|
-
.and emit_notification("delayed.job.workable_count").with_payload(
|
|
167
|
-
.and emit_notification("delayed.job.
|
|
168
|
-
.and emit_notification("delayed.job.
|
|
169
|
-
.and emit_notification("delayed.job.
|
|
170
|
-
.and emit_notification("delayed.job.
|
|
171
|
-
.and emit_notification("delayed.job.
|
|
172
|
-
.and emit_notification("delayed.job.
|
|
173
|
-
.and emit_notification("delayed.job.
|
|
174
|
-
.and emit_notification("delayed.job.
|
|
175
|
-
.and emit_notification("delayed.job.
|
|
176
|
-
.and emit_notification("delayed.job.
|
|
177
|
-
.and emit_notification("delayed.job.
|
|
178
|
-
.and emit_notification("delayed.job.
|
|
179
|
-
.and emit_notification("delayed.job.alert_age_percent").with_payload(
|
|
180
|
-
.and emit_notification("delayed.job.workable_count").with_payload(p30_payload.merge(queue: 'banana')).with_value(1)
|
|
181
|
-
.and emit_notification("delayed.job.max_age").with_payload(p30_payload.merge(queue: 'banana')).with_value(4.hours)
|
|
44
|
+
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
45
|
+
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
46
|
+
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
47
|
+
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
48
|
+
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
49
|
+
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
50
|
+
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
51
|
+
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
52
|
+
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
53
|
+
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
54
|
+
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
55
|
+
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
56
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
57
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
58
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
59
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
60
|
+
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
61
|
+
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
62
|
+
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
63
|
+
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
64
|
+
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
65
|
+
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
66
|
+
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
67
|
+
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
68
|
+
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'interactive')).with_value(0)
|
|
69
|
+
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'user_visible')).with_value(0)
|
|
70
|
+
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'eventual')).with_value(0)
|
|
71
|
+
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'reporting')).with_value(0)
|
|
72
|
+
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'interactive')).approximately.with_value(0)
|
|
73
|
+
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'user_visible')).approximately.with_value(0)
|
|
74
|
+
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'eventual')).approximately.with_value(0)
|
|
75
|
+
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'reporting')).approximately.with_value(0)
|
|
76
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'interactive')).approximately.with_value(0)
|
|
77
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'user_visible')).approximately.with_value(0)
|
|
78
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'eventual')).approximately.with_value(0)
|
|
79
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'reporting')).approximately.with_value(0)
|
|
80
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'interactive')).approximately.with_value(0)
|
|
81
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'user_visible')).approximately.with_value(0)
|
|
82
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'eventual')).approximately.with_value(0)
|
|
83
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'reporting')).approximately.with_value(0)
|
|
182
84
|
end
|
|
183
85
|
|
|
184
86
|
context 'when named priorities are customized' do
|
|
185
87
|
around do |example|
|
|
186
|
-
Delayed::Priority.names = { high: 0, low:
|
|
88
|
+
Delayed::Priority.names = { high: 0, low: 7 }
|
|
187
89
|
example.run
|
|
188
90
|
ensure
|
|
189
91
|
Delayed::Priority.names = nil
|
|
190
92
|
end
|
|
191
|
-
|
|
192
|
-
|
|
93
|
+
|
|
94
|
+
it 'emits empty metrics for all custom priorities' do
|
|
95
|
+
expect { subject.run! }
|
|
96
|
+
.to emit_notification("delayed.monitor.run").with_payload(default_payload.except(:queue))
|
|
97
|
+
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
98
|
+
.and emit_notification("delayed.job.count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
99
|
+
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
100
|
+
.and emit_notification("delayed.job.future_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
101
|
+
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
102
|
+
.and emit_notification("delayed.job.locked_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
103
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
104
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
105
|
+
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
106
|
+
.and emit_notification("delayed.job.failed_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
107
|
+
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
108
|
+
.and emit_notification("delayed.job.working_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
109
|
+
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
110
|
+
.and emit_notification("delayed.job.workable_count").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
111
|
+
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'high')).approximately.with_value(0)
|
|
112
|
+
.and emit_notification("delayed.job.max_age").with_payload(default_payload.merge(priority: 'low')).approximately.with_value(0)
|
|
113
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'high')).approximately.with_value(0)
|
|
114
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(default_payload.merge(priority: 'low')).approximately.with_value(0)
|
|
115
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'high')).with_value(0)
|
|
116
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(default_payload.merge(priority: 'low')).with_value(0)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context 'when there are jobs in the queue' do
|
|
121
|
+
let(:job_attributes) do
|
|
122
|
+
{
|
|
123
|
+
run_at: now,
|
|
124
|
+
queue: 'default',
|
|
125
|
+
handler: "--- !ruby/object:SimpleJob\n",
|
|
126
|
+
attempts: 0,
|
|
127
|
+
}
|
|
128
|
+
end
|
|
129
|
+
let(:failed_attributes) { { run_at: now - 1.week, attempts: 1, failed_at: now - 1.day, locked_at: now - 1.day } }
|
|
130
|
+
let(:p0_attributes) { job_attributes.merge(priority: 1, attempts: 1) }
|
|
131
|
+
let(:p10_attributes) { job_attributes.merge(priority: 13, locked_at: now - 1.day) }
|
|
132
|
+
let(:p20_attributes) { job_attributes.merge(priority: 23, attempts: 1) }
|
|
133
|
+
let(:p30_attributes) { job_attributes.merge(priority: 999, locked_at: now - 1.day) }
|
|
134
|
+
let(:p0_payload) { default_payload.merge(priority: 'interactive') }
|
|
135
|
+
let(:p10_payload) { default_payload.merge(priority: 'user_visible') }
|
|
136
|
+
let(:p20_payload) { default_payload.merge(priority: 'eventual') }
|
|
137
|
+
let(:p30_payload) { default_payload.merge(priority: 'reporting') }
|
|
138
|
+
let!(:p0_workable_job) { Delayed::Job.create! p0_attributes.merge(run_at: now - 30.seconds) }
|
|
139
|
+
let!(:p0_failed_job) { Delayed::Job.create! p0_attributes.merge(failed_attributes) }
|
|
140
|
+
let!(:p0_future_job) { Delayed::Job.create! p0_attributes.merge(run_at: now + 1.hour) }
|
|
141
|
+
let!(:p0_working_job) { Delayed::Job.create! p0_attributes.merge(locked_at: now - 3.minutes) }
|
|
142
|
+
let!(:p10_workable_job) { Delayed::Job.create! p10_attributes.merge(run_at: now - 2.minutes) }
|
|
143
|
+
let!(:p10_failed_job) { Delayed::Job.create! p10_attributes.merge(failed_attributes) }
|
|
144
|
+
let!(:p10_future_job) { Delayed::Job.create! p10_attributes.merge(run_at: now + 1.hour) }
|
|
145
|
+
let!(:p10_working_job) { Delayed::Job.create! p10_attributes.merge(locked_at: now - 7.minutes) }
|
|
146
|
+
let!(:p20_workable_job) { Delayed::Job.create! p20_attributes.merge(run_at: now - 1.hour) }
|
|
147
|
+
let!(:p20_failed_job) { Delayed::Job.create! p20_attributes.merge(failed_attributes) }
|
|
148
|
+
let!(:p20_future_job) { Delayed::Job.create! p20_attributes.merge(run_at: now + 1.hour) }
|
|
149
|
+
let!(:p20_working_job) { Delayed::Job.create! p20_attributes.merge(locked_at: now - 9.minutes) }
|
|
150
|
+
let!(:p30_workable_job) { Delayed::Job.create! p30_attributes.merge(run_at: now - 6.hours) }
|
|
151
|
+
let!(:p30_failed_job) { Delayed::Job.create! p30_attributes.merge(failed_attributes) }
|
|
152
|
+
let!(:p30_future_job) { Delayed::Job.create! p30_attributes.merge(run_at: now + 1.hour) }
|
|
153
|
+
let!(:p30_working_job) { Delayed::Job.create! p30_attributes.merge(locked_at: now - 11.minutes) }
|
|
154
|
+
let!(:p30_workable_job_in_other_queue) { Delayed::Job.create! p30_attributes.merge(run_at: now - 4.hours, queue: 'banana') }
|
|
193
155
|
|
|
194
156
|
it 'emits the expected results for each metric' do
|
|
195
157
|
expect { subject.run! }
|
|
196
158
|
.to emit_notification("delayed.monitor.run").with_payload(default_payload.except(:queue))
|
|
197
|
-
.and emit_notification("delayed.job.count").with_payload(p0_payload).with_value(
|
|
198
|
-
.and emit_notification("delayed.job.future_count").with_payload(p0_payload).with_value(
|
|
199
|
-
.and emit_notification("delayed.job.locked_count").with_payload(p0_payload).with_value(
|
|
159
|
+
.and emit_notification("delayed.job.count").with_payload(p0_payload).with_value(4)
|
|
160
|
+
.and emit_notification("delayed.job.future_count").with_payload(p0_payload).with_value(1)
|
|
161
|
+
.and emit_notification("delayed.job.locked_count").with_payload(p0_payload).with_value(1)
|
|
200
162
|
.and emit_notification("delayed.job.erroring_count").with_payload(p0_payload).with_value(3)
|
|
201
|
-
.and emit_notification("delayed.job.failed_count").with_payload(p0_payload).with_value(
|
|
202
|
-
.and emit_notification("delayed.job.working_count").with_payload(p0_payload).with_value(
|
|
203
|
-
.and emit_notification("delayed.job.workable_count").with_payload(p0_payload).with_value(
|
|
204
|
-
.and emit_notification("delayed.job.max_age").with_payload(p0_payload).with_value(
|
|
205
|
-
.and emit_notification("delayed.job.max_lock_age").with_payload(p0_payload).with_value(
|
|
206
|
-
.and emit_notification("delayed.job.alert_age_percent").with_payload(p0_payload).with_value(0)
|
|
207
|
-
.and emit_notification("delayed.job.count").with_payload(
|
|
208
|
-
.and emit_notification("delayed.job.future_count").with_payload(
|
|
209
|
-
.and emit_notification("delayed.job.locked_count").with_payload(
|
|
163
|
+
.and emit_notification("delayed.job.failed_count").with_payload(p0_payload).with_value(1)
|
|
164
|
+
.and emit_notification("delayed.job.working_count").with_payload(p0_payload).with_value(1)
|
|
165
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p0_payload).with_value(1)
|
|
166
|
+
.and emit_notification("delayed.job.max_age").with_payload(p0_payload).approximately.with_value(30.seconds)
|
|
167
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(p0_payload).approximately.with_value(3.minutes)
|
|
168
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p0_payload).approximately.with_value(30.0.seconds / 1.minute * 100)
|
|
169
|
+
.and emit_notification("delayed.job.count").with_payload(p10_payload).with_value(4)
|
|
170
|
+
.and emit_notification("delayed.job.future_count").with_payload(p10_payload).with_value(1)
|
|
171
|
+
.and emit_notification("delayed.job.locked_count").with_payload(p10_payload).with_value(1)
|
|
172
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(p10_payload).with_value(0)
|
|
173
|
+
.and emit_notification("delayed.job.failed_count").with_payload(p10_payload).with_value(1)
|
|
174
|
+
.and emit_notification("delayed.job.working_count").with_payload(p10_payload).with_value(1)
|
|
175
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p10_payload).with_value(1)
|
|
176
|
+
.and emit_notification("delayed.job.max_age").with_payload(p10_payload).approximately.with_value(2.minutes)
|
|
177
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(p10_payload).approximately.with_value(7.minutes)
|
|
178
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p10_payload).approximately.with_value(2.0.minutes / 3.minutes * 100)
|
|
179
|
+
.and emit_notification("delayed.job.count").with_payload(p20_payload).with_value(4)
|
|
180
|
+
.and emit_notification("delayed.job.future_count").with_payload(p20_payload).with_value(1)
|
|
181
|
+
.and emit_notification("delayed.job.locked_count").with_payload(p20_payload).with_value(1)
|
|
210
182
|
.and emit_notification("delayed.job.erroring_count").with_payload(p20_payload).with_value(3)
|
|
211
|
-
.and emit_notification("delayed.job.failed_count").with_payload(p20_payload).with_value(
|
|
212
|
-
.and emit_notification("delayed.job.working_count").with_payload(p20_payload).with_value(
|
|
213
|
-
.and emit_notification("delayed.job.workable_count").with_payload(p20_payload).with_value(
|
|
214
|
-
.and emit_notification("delayed.job.max_age").with_payload(p20_payload).with_value(
|
|
215
|
-
.and emit_notification("delayed.job.max_lock_age").with_payload(p20_payload).with_value(
|
|
216
|
-
.and emit_notification("delayed.job.alert_age_percent").with_payload(p20_payload).with_value(
|
|
217
|
-
.and emit_notification("delayed.job.
|
|
218
|
-
.and emit_notification("delayed.job.
|
|
183
|
+
.and emit_notification("delayed.job.failed_count").with_payload(p20_payload).with_value(1)
|
|
184
|
+
.and emit_notification("delayed.job.working_count").with_payload(p20_payload).with_value(1)
|
|
185
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p20_payload).with_value(1)
|
|
186
|
+
.and emit_notification("delayed.job.max_age").with_payload(p20_payload).approximately.with_value(1.hour)
|
|
187
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(p20_payload).approximately.with_value(9.minutes)
|
|
188
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p20_payload).approximately.with_value(1.hour / 1.5.hours * 100)
|
|
189
|
+
.and emit_notification("delayed.job.count").with_payload(p30_payload).with_value(4)
|
|
190
|
+
.and emit_notification("delayed.job.future_count").with_payload(p30_payload).with_value(1)
|
|
191
|
+
.and emit_notification("delayed.job.locked_count").with_payload(p30_payload).with_value(1)
|
|
192
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(p30_payload).with_value(0)
|
|
193
|
+
.and emit_notification("delayed.job.failed_count").with_payload(p30_payload).with_value(1)
|
|
194
|
+
.and emit_notification("delayed.job.working_count").with_payload(p30_payload).with_value(1)
|
|
195
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p30_payload).with_value(1)
|
|
196
|
+
.and emit_notification("delayed.job.max_age").with_payload(p30_payload).approximately.with_value(6.hours)
|
|
197
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(p30_payload).approximately.with_value(11.minutes)
|
|
198
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p30_payload).approximately.with_value(100) # 6 hours / 4 hours (overflow)
|
|
199
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p30_payload.merge(queue: 'banana')).with_value(1)
|
|
200
|
+
.and emit_notification("delayed.job.max_age").with_payload(p30_payload.merge(queue: 'banana')).approximately.with_value(4.hours)
|
|
219
201
|
end
|
|
220
202
|
|
|
221
|
-
context 'when
|
|
203
|
+
context 'when named priorities are customized' do
|
|
222
204
|
around do |example|
|
|
223
|
-
Delayed::Priority.
|
|
205
|
+
Delayed::Priority.names = { high: 0, low: 20 }
|
|
224
206
|
example.run
|
|
225
207
|
ensure
|
|
226
|
-
Delayed::Priority.
|
|
208
|
+
Delayed::Priority.names = nil
|
|
227
209
|
end
|
|
210
|
+
let(:p0_payload) { default_payload.merge(priority: 'high') }
|
|
211
|
+
let(:p20_payload) { default_payload.merge(priority: 'low') }
|
|
228
212
|
|
|
229
|
-
it 'emits the expected
|
|
213
|
+
it 'emits the expected results for each metric' do
|
|
230
214
|
expect { subject.run! }
|
|
231
|
-
.to emit_notification("delayed.
|
|
232
|
-
.and emit_notification("delayed.job.
|
|
215
|
+
.to emit_notification("delayed.monitor.run").with_payload(default_payload.except(:queue))
|
|
216
|
+
.and emit_notification("delayed.job.count").with_payload(p0_payload).with_value(8)
|
|
217
|
+
.and emit_notification("delayed.job.future_count").with_payload(p0_payload).with_value(2)
|
|
218
|
+
.and emit_notification("delayed.job.locked_count").with_payload(p0_payload).with_value(2)
|
|
219
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(p0_payload).with_value(3)
|
|
220
|
+
.and emit_notification("delayed.job.failed_count").with_payload(p0_payload).with_value(2)
|
|
221
|
+
.and emit_notification("delayed.job.working_count").with_payload(p0_payload).with_value(2)
|
|
222
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p0_payload).with_value(2)
|
|
223
|
+
.and emit_notification("delayed.job.max_age").with_payload(p0_payload).approximately.with_value(2.minutes)
|
|
224
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(p0_payload).approximately.with_value(7.minutes)
|
|
225
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p0_payload).approximately.with_value(0)
|
|
226
|
+
.and emit_notification("delayed.job.count").with_payload(p20_payload).with_value(8)
|
|
227
|
+
.and emit_notification("delayed.job.future_count").with_payload(p20_payload).with_value(2)
|
|
228
|
+
.and emit_notification("delayed.job.locked_count").with_payload(p20_payload).with_value(2)
|
|
229
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(p20_payload).with_value(3)
|
|
230
|
+
.and emit_notification("delayed.job.failed_count").with_payload(p20_payload).with_value(2)
|
|
231
|
+
.and emit_notification("delayed.job.working_count").with_payload(p20_payload).with_value(2)
|
|
232
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p20_payload).with_value(2)
|
|
233
|
+
.and emit_notification("delayed.job.max_age").with_payload(p20_payload).approximately.with_value(6.hours)
|
|
234
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(p20_payload).approximately.with_value(11.minutes)
|
|
235
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p20_payload).approximately.with_value(0)
|
|
236
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p20_payload.merge(queue: 'banana')).with_value(1)
|
|
237
|
+
.and emit_notification("delayed.job.max_age").with_payload(p20_payload.merge(queue: 'banana')).approximately.with_value(4.hours)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
context 'when alert thresholds are specified' do
|
|
241
|
+
around do |example|
|
|
242
|
+
Delayed::Priority.alerts = { high: { age: 3.hours }, low: { age: 1.year } }
|
|
243
|
+
example.run
|
|
244
|
+
ensure
|
|
245
|
+
Delayed::Priority.alerts = nil
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it 'emits the expected alert_age_percent results' do
|
|
249
|
+
expect { subject.run! }
|
|
250
|
+
.to emit_notification("delayed.job.alert_age_percent").with_payload(p0_payload).approximately.with_value(2.0.minutes / 3.hours * 100)
|
|
251
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p20_payload).approximately.with_value(6.0.hours / 1.year * 100)
|
|
252
|
+
end
|
|
233
253
|
end
|
|
234
254
|
end
|
|
235
|
-
end
|
|
236
255
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
256
|
+
context 'when worker queues are specified' do
|
|
257
|
+
around do |example|
|
|
258
|
+
Delayed::Worker.queues = %w(banana gram)
|
|
259
|
+
Delayed::Priority.names = { interactive: 0 } # avoid splitting by priority for simplicity
|
|
260
|
+
Delayed::Priority.alerts = { interactive: { age: 8.hours } }
|
|
261
|
+
example.run
|
|
262
|
+
ensure
|
|
263
|
+
Delayed::Priority.names = nil
|
|
264
|
+
Delayed::Worker.queues = []
|
|
265
|
+
end
|
|
266
|
+
let(:banana_payload) { default_payload.merge(queue: 'banana', priority: 'interactive') }
|
|
267
|
+
let(:gram_payload) { default_payload.merge(queue: 'gram', priority: 'interactive') }
|
|
268
|
+
|
|
269
|
+
it 'emits the expected results for each queue' do
|
|
270
|
+
expect { subject.run! }
|
|
271
|
+
.to emit_notification("delayed.monitor.run").with_payload(default_payload.except(:queue))
|
|
272
|
+
.and emit_notification("delayed.job.count").with_payload(banana_payload).with_value(1)
|
|
273
|
+
.and emit_notification("delayed.job.future_count").with_payload(banana_payload).with_value(0)
|
|
274
|
+
.and emit_notification("delayed.job.locked_count").with_payload(banana_payload).with_value(0)
|
|
275
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(banana_payload).with_value(0)
|
|
276
|
+
.and emit_notification("delayed.job.failed_count").with_payload(banana_payload).with_value(0)
|
|
277
|
+
.and emit_notification("delayed.job.working_count").with_payload(banana_payload).with_value(0)
|
|
278
|
+
.and emit_notification("delayed.job.workable_count").with_payload(banana_payload).with_value(1)
|
|
279
|
+
.and emit_notification("delayed.job.max_age").with_payload(banana_payload).approximately.with_value(4.hours)
|
|
280
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(banana_payload).approximately.with_value(0)
|
|
281
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(banana_payload).approximately.with_value(4.0.hours / 8.hours * 100)
|
|
282
|
+
.and emit_notification("delayed.job.count").with_payload(gram_payload).with_value(0)
|
|
283
|
+
.and emit_notification("delayed.job.future_count").with_payload(gram_payload).with_value(0)
|
|
284
|
+
.and emit_notification("delayed.job.locked_count").with_payload(gram_payload).with_value(0)
|
|
285
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(gram_payload).with_value(0)
|
|
286
|
+
.and emit_notification("delayed.job.failed_count").with_payload(gram_payload).with_value(0)
|
|
287
|
+
.and emit_notification("delayed.job.working_count").with_payload(gram_payload).with_value(0)
|
|
288
|
+
.and emit_notification("delayed.job.workable_count").with_payload(gram_payload).with_value(0)
|
|
289
|
+
.and emit_notification("delayed.job.max_age").with_payload(gram_payload).approximately.with_value(0)
|
|
290
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(gram_payload).approximately.with_value(0)
|
|
291
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(gram_payload).approximately.with_value(0)
|
|
292
|
+
end
|
|
246
293
|
end
|
|
247
|
-
let(:banana_payload) { default_payload.merge(queue: 'banana', priority: 'interactive') }
|
|
248
|
-
let(:gram_payload) { default_payload.merge(queue: 'gram', priority: 'interactive') }
|
|
249
294
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
295
|
+
context 'when using app-local timezone for DB timestamps' do
|
|
296
|
+
let(:app_local_db_time) { true }
|
|
297
|
+
|
|
298
|
+
it 'emits the expected results for each metric' do
|
|
299
|
+
expect { subject.run! }
|
|
300
|
+
.to emit_notification("delayed.monitor.run").with_payload(default_payload.except(:queue))
|
|
301
|
+
.and emit_notification("delayed.job.count").with_payload(p0_payload).with_value(4)
|
|
302
|
+
.and emit_notification("delayed.job.future_count").with_payload(p0_payload).with_value(1)
|
|
303
|
+
.and emit_notification("delayed.job.locked_count").with_payload(p0_payload).with_value(1)
|
|
304
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(p0_payload).with_value(3)
|
|
305
|
+
.and emit_notification("delayed.job.failed_count").with_payload(p0_payload).with_value(1)
|
|
306
|
+
.and emit_notification("delayed.job.working_count").with_payload(p0_payload).with_value(1)
|
|
307
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p0_payload).with_value(1)
|
|
308
|
+
.and emit_notification("delayed.job.max_age").with_payload(p0_payload).approximately.with_value(30.seconds)
|
|
309
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(p0_payload).approximately.with_value(3.minutes)
|
|
310
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p0_payload).approximately.with_value(30.0.seconds / 1.minute * 100)
|
|
311
|
+
.and emit_notification("delayed.job.count").with_payload(p10_payload).with_value(4)
|
|
312
|
+
.and emit_notification("delayed.job.future_count").with_payload(p10_payload).with_value(1)
|
|
313
|
+
.and emit_notification("delayed.job.locked_count").with_payload(p10_payload).with_value(1)
|
|
314
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(p10_payload).with_value(0)
|
|
315
|
+
.and emit_notification("delayed.job.failed_count").with_payload(p10_payload).with_value(1)
|
|
316
|
+
.and emit_notification("delayed.job.working_count").with_payload(p10_payload).with_value(1)
|
|
317
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p10_payload).with_value(1)
|
|
318
|
+
.and emit_notification("delayed.job.max_age").with_payload(p10_payload).approximately.with_value(2.minutes)
|
|
319
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(p10_payload).approximately.with_value(7.minutes)
|
|
320
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p10_payload).approximately.with_value(2.0.minutes / 3.minutes * 100)
|
|
321
|
+
.and emit_notification("delayed.job.count").with_payload(p20_payload).with_value(4)
|
|
322
|
+
.and emit_notification("delayed.job.future_count").with_payload(p20_payload).with_value(1)
|
|
323
|
+
.and emit_notification("delayed.job.locked_count").with_payload(p20_payload).with_value(1)
|
|
324
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(p20_payload).with_value(3)
|
|
325
|
+
.and emit_notification("delayed.job.failed_count").with_payload(p20_payload).with_value(1)
|
|
326
|
+
.and emit_notification("delayed.job.working_count").with_payload(p20_payload).with_value(1)
|
|
327
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p20_payload).with_value(1)
|
|
328
|
+
.and emit_notification("delayed.job.max_age").with_payload(p20_payload).approximately.with_value(1.hour)
|
|
329
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(p20_payload).approximately.with_value(9.minutes)
|
|
330
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p20_payload).approximately.with_value(1.hour / 1.5.hours * 100)
|
|
331
|
+
.and emit_notification("delayed.job.count").with_payload(p30_payload).with_value(4)
|
|
332
|
+
.and emit_notification("delayed.job.future_count").with_payload(p30_payload).with_value(1)
|
|
333
|
+
.and emit_notification("delayed.job.locked_count").with_payload(p30_payload).with_value(1)
|
|
334
|
+
.and emit_notification("delayed.job.erroring_count").with_payload(p30_payload).with_value(0)
|
|
335
|
+
.and emit_notification("delayed.job.failed_count").with_payload(p30_payload).with_value(1)
|
|
336
|
+
.and emit_notification("delayed.job.working_count").with_payload(p30_payload).with_value(1)
|
|
337
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p30_payload).with_value(1)
|
|
338
|
+
.and emit_notification("delayed.job.max_age").with_payload(p30_payload).approximately.with_value(6.hours)
|
|
339
|
+
.and emit_notification("delayed.job.max_lock_age").with_payload(p30_payload).approximately.with_value(11.minutes)
|
|
340
|
+
.and emit_notification("delayed.job.alert_age_percent").with_payload(p30_payload).approximately.with_value(100) # 6 hours / 4 hours (overflow)
|
|
341
|
+
.and emit_notification("delayed.job.workable_count").with_payload(p30_payload.merge(queue: 'banana')).with_value(1)
|
|
342
|
+
.and emit_notification("delayed.job.max_age").with_payload(p30_payload.merge(queue: 'banana')).approximately.with_value(4.hours)
|
|
343
|
+
end
|
|
273
344
|
end
|
|
274
345
|
end
|
|
275
346
|
end
|
|
276
347
|
|
|
277
|
-
describe '
|
|
348
|
+
describe 'SQL' do
|
|
278
349
|
let(:monitor) { described_class.new }
|
|
279
350
|
let(:queries) { [] }
|
|
280
351
|
let(:now) { '2025-11-10 17:20:13 UTC' }
|
|
@@ -289,30 +360,28 @@ RSpec.describe Delayed::Monitor do
|
|
|
289
360
|
value = value.value if value.is_a?(ActiveModel::Attribute)
|
|
290
361
|
sql = sql.sub(/(\?|\$\d)/, ActiveRecord::Base.connection.quote(value))
|
|
291
362
|
end
|
|
292
|
-
queries << sql
|
|
363
|
+
queries << QueryUnderTest.for(sql)
|
|
364
|
+
queries << "---"
|
|
293
365
|
end
|
|
294
366
|
end
|
|
295
367
|
|
|
296
|
-
def
|
|
297
|
-
|
|
298
|
-
|
|
368
|
+
def query_descriptions
|
|
369
|
+
described_class::METRICS.each do |metric|
|
|
370
|
+
queries << "-- QUERIES FOR `#{metric}`:"
|
|
371
|
+
queries << "---------------------------------"
|
|
372
|
+
monitor.query_for(metric)
|
|
373
|
+
queries << "-- (no new queries)" unless queries.last == '---'
|
|
374
|
+
end
|
|
375
|
+
queries.dup.map { |query| query.try(:full_description) || query }
|
|
299
376
|
end
|
|
300
377
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
expect(queries_for(metric).map(&:formatted).join("\n")).to match_snapshot
|
|
305
|
-
end
|
|
306
|
-
|
|
307
|
-
it "produces the expected #{current_adapter} query plan for #{metric}" do
|
|
308
|
-
expect(queries_for(metric).map(&:explain).join("\n")).to match_snapshot
|
|
309
|
-
end
|
|
378
|
+
it "runs the expected #{current_adapter} queries with the expected plans" do
|
|
379
|
+
expect(query_descriptions.join("\n")).to match_snapshot
|
|
380
|
+
end
|
|
310
381
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
end
|
|
315
|
-
end
|
|
382
|
+
context 'when using the legacy index', :with_legacy_table_index do
|
|
383
|
+
it "[legacy index] runs the expected #{current_adapter} queries with the expected plans" do
|
|
384
|
+
expect(query_descriptions.join("\n")).to match_snapshot
|
|
316
385
|
end
|
|
317
386
|
end
|
|
318
387
|
end
|