que-scheduler 3.4.3 → 4.1.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/README.md +72 -31
- data/lib/que/scheduler.rb +2 -1
- data/lib/que/scheduler/configuration.rb +34 -0
- data/lib/que/scheduler/db.rb +3 -1
- data/lib/que/scheduler/defined_job.rb +2 -2
- data/lib/que/scheduler/jobs/que_scheduler_audit_clear_down_job.rb +2 -2
- data/lib/que/scheduler/migrations.rb +5 -0
- data/lib/que/scheduler/migrations/6/down.sql +7 -0
- data/lib/que/scheduler/migrations/6/up.sql +26 -0
- data/lib/que/scheduler/schedule.rb +25 -17
- data/lib/que/scheduler/scheduler_job.rb +6 -5
- data/lib/que/scheduler/scheduler_job_args.rb +2 -1
- data/lib/que/scheduler/state_checks.rb +1 -17
- data/lib/que/scheduler/time_zone.rb +61 -0
- data/lib/que/scheduler/to_enqueue.rb +12 -8
- data/lib/que/scheduler/version.rb +1 -1
- data/lib/que/scheduler/version_support.rb +5 -1
- metadata +27 -10
- data/lib/que/scheduler/config.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a75db11d923c140204bd92360916e4cacaac5531fc25470616a4d558dde22dd3
|
4
|
+
data.tar.gz: ba08caa1a8bf8a87532da3fa5cbfc8b720784e88354ab74b240c5d724c46fb07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19ad5f4284dd03b6129d970e87cdd1652f8e992a5c141c032fc4935beaea2bbf15f35253c5c5f6c93e3cf6b32875beb6138112d43e8e5e123235c32fa9593984
|
7
|
+
data.tar.gz: f8618b848befcccf03387fe2e891f201790c1dc8b736406a62bd3d63990ac1c8f47737966103713d843a627ec39d2ff23128570dd6b03cd28682bc4613638fcf
|
data/README.md
CHANGED
@@ -28,7 +28,7 @@ resque-scheduler files, but with additional features.
|
|
28
28
|
```ruby
|
29
29
|
class CreateQueSchedulerSchema < ActiveRecord::Migration
|
30
30
|
def change
|
31
|
-
Que::Scheduler::Migrations.migrate!(version:
|
31
|
+
Que::Scheduler::Migrations.migrate!(version: 6)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
```
|
@@ -36,8 +36,8 @@ resque-scheduler files, but with additional features.
|
|
36
36
|
## Schedule configuration
|
37
37
|
|
38
38
|
The schedule file should be placed here: `config/que_schedule.yml`. Alternatively if you
|
39
|
-
wish to generate the configuration dynamically, you can set it directly
|
40
|
-
|
39
|
+
wish to generate the configuration dynamically, you can set it directly using an initializer
|
40
|
+
(see "Gem configuration" below).
|
41
41
|
|
42
42
|
The file is a list of que job classes with arguments and a schedule frequency (in crontab
|
43
43
|
syntax). The format is similar to the resque-scheduler format, though priorities must be supplied as
|
@@ -135,19 +135,42 @@ A job can have a `schedule_type` assigned to it. Valid values are:
|
|
135
135
|
|
136
136
|
## Gem configuration
|
137
137
|
|
138
|
-
You can configure some aspects of the gem with
|
138
|
+
You can configure some aspects of the gem with a config block (eg in a Rails initializer).
|
139
|
+
The default is given below. You can omit any configuration sections you are not intending to change.
|
140
|
+
It is quite likely you won't have to create this config at all.
|
139
141
|
|
140
142
|
```ruby
|
141
143
|
Que::Scheduler.configure do |config|
|
142
144
|
# The location of the schedule yaml file.
|
143
|
-
config.schedule_location = ENV.fetch(
|
145
|
+
config.schedule_location = ENV.fetch("QUE_SCHEDULER_CONFIG_LOCATION", "config/que_schedule.yml")
|
146
|
+
|
147
|
+
# The schedule as a hash. You can use this if you want to build the schedule yourself at runtime.
|
148
|
+
# This will override the above value if provided.
|
149
|
+
config.schedule = {
|
150
|
+
SpecifiedByHashTestJob: {
|
151
|
+
cron: "02 11 * * *"
|
152
|
+
}
|
153
|
+
}
|
144
154
|
|
145
|
-
#
|
146
|
-
# However
|
155
|
+
# The transaction block adapter. By default, que-scheduler uses the one supplied by que.
|
156
|
+
# However if, for example, you rely on listeners to ActiveRecord's exact `transaction` method, or
|
147
157
|
# Sequel's DB.after_commit helper, then you can supply it here.
|
148
158
|
config.transaction_adapter = ::Que.method(:transaction)
|
149
|
-
end
|
150
159
|
|
160
|
+
# Which queue name the que-scheduler job should self-schedule on. Typically this is the default
|
161
|
+
# queue of que, which has a different name in Que 0.x ("") and 1.x ("default").
|
162
|
+
# It *must* be the "highest throughput" queue - do not work the scheduler on a "long
|
163
|
+
# running jobs" queue. It is very unlikely you will want to change this.
|
164
|
+
config.que_scheduler_queue = ENV.fetch("QUE_SCHEDULER_QUEUE", "" or "default")
|
165
|
+
|
166
|
+
# If que-scheduler is being used with Rails, then it will inherit the time zone from that
|
167
|
+
# framework, and you can leave the value as nil as shown below. However, if you are not using
|
168
|
+
# Rails, you may need to set the time zone here. If que-scheduler cannot determine the time zone
|
169
|
+
# it will yield an error prompting you for action.
|
170
|
+
# If you need to set a value, use the string representation:
|
171
|
+
# eg: config.time_zone = "Europe/London"
|
172
|
+
config.time_zone = nil
|
173
|
+
end
|
151
174
|
```
|
152
175
|
|
153
176
|
## Scheduler Audit
|
@@ -159,9 +182,29 @@ migration tasks.
|
|
159
182
|
Additionally, there is the audit table `que_scheduler_audit_enqueued`. This logs every job that
|
160
183
|
the scheduler enqueues.
|
161
184
|
|
185
|
+
que-scheduler comes with the `QueSchedulerAuditClearDownJob` job built in that you can optionally
|
186
|
+
schedule to clear down audit rows if you don't need to retain them indefinitely. You should add this
|
187
|
+
to your own scheduler config yaml.
|
188
|
+
|
189
|
+
For example:
|
190
|
+
|
191
|
+
```yaml
|
192
|
+
# This will clear down the oldest que-scheduler audit rows. Since que-scheduler
|
193
|
+
# runs approximately every minute, 129600 is 90 days.
|
194
|
+
Que::Scheduler::Jobs::QueSchedulerAuditClearDownJob:
|
195
|
+
cron: "0 0 * * *"
|
196
|
+
args:
|
197
|
+
retain_row_count: 129600
|
198
|
+
```
|
199
|
+
|
200
|
+
## Required migrations
|
201
|
+
|
162
202
|
When there is a major version (breaking) change, a migration should be run in. The version of the
|
163
|
-
migration proceeds at a faster rate than the version of the gem.
|
164
|
-
|
203
|
+
latest migration proceeds at a faster rate than the version of the gem. eg If the gem is on version
|
204
|
+
3 then the migrations may be on version 6).
|
205
|
+
|
206
|
+
To run in all the migrations required up to a number, just migrate to that number with one line, and
|
207
|
+
it will perform all the intermediary steps.
|
165
208
|
|
166
209
|
ie, This will perform all migrations necessary up to the latest version, skipping any already
|
167
210
|
performed.
|
@@ -169,7 +212,7 @@ performed.
|
|
169
212
|
```ruby
|
170
213
|
class CreateQueSchedulerSchema < ActiveRecord::Migration
|
171
214
|
def change
|
172
|
-
Que::Scheduler::Migrations.migrate!(version:
|
215
|
+
Que::Scheduler::Migrations.migrate!(version: 6)
|
173
216
|
end
|
174
217
|
end
|
175
218
|
```
|
@@ -183,22 +226,15 @@ The changes in past migrations were:
|
|
183
226
|
| 3 | Added the audit table `que_scheduler_audit_enqueued`. |
|
184
227
|
| 4 | Updated the the audit tables to use bigints |
|
185
228
|
| 5 | Dropped an unnecessary index |
|
229
|
+
| 6 | Enforced single scheduler job at the trigger level |
|
186
230
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
to your own scheduler config yaml.
|
231
|
+
The changes to the DB ([DDL](https://en.wikipedia.org/wiki/Data_definition_language)) are all
|
232
|
+
captured in the structure.sql so will be re-run in correctly if squashed - except for the actual
|
233
|
+
scheduling of the job itself (as that is [DML](https://en.wikipedia.org/wiki/Data_manipulation_language)).
|
234
|
+
If you squash your migrations make sure this is added as the final line:
|
192
235
|
|
193
|
-
|
194
|
-
|
195
|
-
```yaml
|
196
|
-
# This will clear down the oldest que-scheduler audit rows. Since que-scheduler
|
197
|
-
# runs approximately every minute, 129600 is 90 days.
|
198
|
-
Que::Scheduler::Jobs::QueSchedulerAuditClearDownJob:
|
199
|
-
cron: "0 0 * * *"
|
200
|
-
args:
|
201
|
-
retain_row_count: 129600
|
236
|
+
```ruby
|
237
|
+
Que::Scheduler::Migrations.reenqueue_scheduler_if_missing
|
202
238
|
```
|
203
239
|
|
204
240
|
## HA Redundancy and DB restores
|
@@ -214,8 +250,8 @@ in a coherent state with the rest of your database.
|
|
214
250
|
## Concurrent scheduler detection
|
215
251
|
|
216
252
|
No matter how many tasks you have defined in your schedule, you will only ever need one que-scheduler
|
217
|
-
job enqueued. que-scheduler knows this, and
|
218
|
-
|
253
|
+
job enqueued. que-scheduler knows this, and there are DB constraints in place to ensure there is
|
254
|
+
only ever exactly one scheduler job.
|
219
255
|
|
220
256
|
It also follows que job design [best practices](https://github.com/chanks/que/blob/master/docs/writing_reliable_jobs.md),
|
221
257
|
using ACID guarantees, to ensure that it will never run multiple times. If the scheduler crashes for any reason,
|
@@ -267,9 +303,13 @@ The scheduler will then continue to retry indefinitely.
|
|
267
303
|
que-scheduler uses [semantic versioning](https://semver.org/), so major version changes will usually
|
268
304
|
require additional actions to be taken upgrading from one major version to another.
|
269
305
|
|
306
|
+
## Changelog
|
307
|
+
|
308
|
+
A full changelog can be found here: [CHANGELOG.md](https://github.com/hlascelles/que-scheduler/blob/master/CHANGELOG.md)
|
309
|
+
|
270
310
|
## System requirements
|
271
311
|
|
272
|
-
Your [postgres](https://www.postgresql.org/) database must be at least version 9.
|
312
|
+
Your [postgres](https://www.postgresql.org/) database must be at least version 9.5.0.
|
273
313
|
|
274
314
|
## Inspiration
|
275
315
|
|
@@ -277,9 +317,10 @@ This gem was inspired by the makers of the excellent [Que](https://github.com/ch
|
|
277
317
|
|
278
318
|
## Contributors
|
279
319
|
|
320
|
+
* @bnauta
|
321
|
+
* @bjeanes
|
322
|
+
* @JackDanger
|
280
323
|
* @jish
|
281
324
|
* @joehorsnell
|
282
|
-
* @bnauta
|
283
|
-
* @papodaca
|
284
325
|
* @krzyzak
|
285
|
-
* @
|
326
|
+
* @papodaca
|
data/lib/que/scheduler.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "que/scheduler/version"
|
2
2
|
require "que/scheduler/version_support"
|
3
|
-
require "que/scheduler/
|
3
|
+
require "que/scheduler/configuration"
|
4
|
+
require "que/scheduler/time_zone"
|
4
5
|
require "que/scheduler/scheduler_job"
|
5
6
|
require "que/scheduler/db"
|
6
7
|
require "que/scheduler/audit"
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "que"
|
2
|
+
require_relative "version_support"
|
3
|
+
|
4
|
+
module Que
|
5
|
+
module Scheduler
|
6
|
+
class Configuration
|
7
|
+
attr_accessor :schedule_location, :schedule, :transaction_adapter, :que_scheduler_queue,
|
8
|
+
:time_zone
|
9
|
+
end
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :configuration
|
13
|
+
|
14
|
+
def configure
|
15
|
+
self.configuration ||= Configuration.new
|
16
|
+
yield(configuration)
|
17
|
+
end
|
18
|
+
|
19
|
+
def apply_defaults
|
20
|
+
configure do |config|
|
21
|
+
config.schedule_location =
|
22
|
+
ENV.fetch("QUE_SCHEDULER_CONFIG_LOCATION", "config/que_schedule.yml")
|
23
|
+
config.transaction_adapter = ::Que.method(:transaction)
|
24
|
+
config.que_scheduler_queue =
|
25
|
+
ENV.fetch("QUE_SCHEDULER_QUEUE", Que::Scheduler::VersionSupport.default_scheduler_queue)
|
26
|
+
config.schedule = nil
|
27
|
+
config.time_zone = nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Que::Scheduler.apply_defaults
|
data/lib/que/scheduler/db.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "
|
3
|
+
require_relative "configuration"
|
4
4
|
|
5
5
|
module Que
|
6
6
|
module Scheduler
|
@@ -18,9 +18,11 @@ module Que
|
|
18
18
|
Que::Scheduler::VersionSupport.execute(NOW_SQL).first.values.first
|
19
19
|
end
|
20
20
|
|
21
|
+
# rubocop:disable Style/ExplicitBlockArgument
|
21
22
|
def transaction
|
22
23
|
Que::Scheduler.configuration.transaction_adapter.call { yield }
|
23
24
|
end
|
25
|
+
# rubocop:enable Style/ExplicitBlockArgument
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -86,10 +86,10 @@ module Que
|
|
86
86
|
# queue name is only supported for a subrange of ActiveJob versions. Print this out as a
|
87
87
|
# warning.
|
88
88
|
if queue &&
|
89
|
-
Que::Scheduler::ToEnqueue.
|
89
|
+
Que::Scheduler::ToEnqueue.active_job_loaded? &&
|
90
90
|
job_class < ::ActiveJob::Base &&
|
91
91
|
Que::Scheduler::ToEnqueue.active_job_version < Gem::Version.create("6.0.3")
|
92
|
-
puts
|
92
|
+
puts <<~ERR
|
93
93
|
WARNING from que-scheduler....
|
94
94
|
Between versions 4.2.3 and 6.0.2 (inclusive) Rails did not support setting queue names
|
95
95
|
on que jobs with ActiveJob, so que-scheduler cannot support it.
|
@@ -8,7 +8,7 @@ module Que
|
|
8
8
|
class QueSchedulerAuditClearDownJob < Que::Job
|
9
9
|
class << self
|
10
10
|
def build_sql(table_name)
|
11
|
-
|
11
|
+
<<~SQL
|
12
12
|
WITH deleted AS (
|
13
13
|
DELETE FROM #{table_name}
|
14
14
|
WHERE scheduler_job_id <= (
|
@@ -28,7 +28,7 @@ module Que
|
|
28
28
|
Que::Scheduler::VersionSupport.set_priority(self, 100)
|
29
29
|
|
30
30
|
def run(options)
|
31
|
-
retain_row_count = options.fetch(:retain_row_count)
|
31
|
+
retain_row_count = options.symbolize_keys.fetch(:retain_row_count)
|
32
32
|
Que::Scheduler::Db.transaction do
|
33
33
|
# This may delete zero or more than `retain_row_count` depending on if anything was
|
34
34
|
# scheduled in each of the past schedule runs
|
@@ -41,6 +41,11 @@ module Que
|
|
41
41
|
result.any?
|
42
42
|
end
|
43
43
|
|
44
|
+
# This method is only intended for use in squashed migrations
|
45
|
+
def reenqueue_scheduler_if_missing
|
46
|
+
Que::Scheduler::SchedulerJob.enqueue if Que::Scheduler::Db.count_schedulers.zero?
|
47
|
+
end
|
48
|
+
|
44
49
|
private
|
45
50
|
|
46
51
|
def migrate_up(current, version)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
-- Ensure there is no more than one scheduler
|
2
|
+
CREATE UNIQUE INDEX que_scheduler_job_in_que_jobs_unique_index ON que_jobs(job_class)
|
3
|
+
WHERE job_class = 'Que::Scheduler::SchedulerJob';
|
4
|
+
|
5
|
+
-- Ensure there is at least one scheduler
|
6
|
+
CREATE OR REPLACE FUNCTION que_scheduler_check_job_exists() RETURNS bool AS $$
|
7
|
+
SELECT EXISTS(SELECT * FROM que_jobs WHERE job_class = 'Que::Scheduler::SchedulerJob');
|
8
|
+
$$ LANGUAGE SQL;
|
9
|
+
|
10
|
+
CREATE OR REPLACE FUNCTION que_scheduler_prevent_job_deletion() RETURNS TRIGGER AS
|
11
|
+
$BODY$
|
12
|
+
DECLARE
|
13
|
+
BEGIN
|
14
|
+
IF OLD.job_class = 'Que::Scheduler::SchedulerJob' THEN
|
15
|
+
IF NOT que_scheduler_check_job_exists() THEN
|
16
|
+
raise exception 'Deletion of que_scheduler job % prevented. Deleting the que_scheduler job is almost certainly a mistake.', OLD.job_id;
|
17
|
+
END IF;
|
18
|
+
END IF;
|
19
|
+
RETURN OLD;
|
20
|
+
END;
|
21
|
+
$BODY$
|
22
|
+
LANGUAGE 'plpgsql';
|
23
|
+
|
24
|
+
CREATE CONSTRAINT TRIGGER que_scheduler_prevent_job_deletion_trigger AFTER UPDATE OR DELETE ON que_jobs
|
25
|
+
DEFERRABLE INITIALLY DEFERRED
|
26
|
+
FOR EACH ROW EXECUTE PROCEDURE que_scheduler_prevent_job_deletion();
|
@@ -1,21 +1,31 @@
|
|
1
|
+
require_relative "configuration"
|
1
2
|
require_relative "defined_job"
|
2
3
|
|
3
4
|
module Que
|
4
5
|
module Scheduler
|
5
6
|
class Schedule
|
6
7
|
class << self
|
8
|
+
# The main method for determining the schedule. It has to evaluate the schedule as late as
|
9
|
+
# possible (ie just as it is about to be used) as we cannot guarantee we are in a Rails
|
10
|
+
# app with initializers. In a future release this may change to "fast fail" in Rails by
|
11
|
+
# checking the config up front.
|
7
12
|
def schedule
|
8
13
|
@schedule ||=
|
9
14
|
begin
|
10
|
-
|
11
|
-
|
15
|
+
configuration = Que::Scheduler.configuration
|
16
|
+
if !configuration.schedule.nil?
|
17
|
+
# If an explicit schedule as a hash has been defined, use that.
|
18
|
+
from_hash(configuration.schedule)
|
19
|
+
elsif File.exist?(configuration.schedule_location)
|
20
|
+
# If the schedule is defined as a file location, then load it and return it.
|
21
|
+
from_file(configuration.schedule_location)
|
22
|
+
else
|
23
|
+
raise "No que-scheduler config set, or file found " \
|
24
|
+
"at #{configuration.schedule_location}"
|
25
|
+
end
|
12
26
|
end
|
13
27
|
end
|
14
28
|
|
15
|
-
def schedule=(schedule_config)
|
16
|
-
@schedule = schedule_config.nil? ? nil : from_yaml(schedule_config)
|
17
|
-
end
|
18
|
-
|
19
29
|
def from_file(location)
|
20
30
|
from_yaml(IO.read(location))
|
21
31
|
end
|
@@ -27,20 +37,19 @@ module Que
|
|
27
37
|
|
28
38
|
def from_hash(config_hash)
|
29
39
|
config_hash.map do |name, defined_job_hash|
|
30
|
-
|
40
|
+
name_str = name.to_s
|
41
|
+
[name_str, hash_item_to_defined_job(name_str, defined_job_hash)]
|
31
42
|
end.to_h
|
32
43
|
end
|
33
44
|
|
34
|
-
def hash_item_to_defined_job(name,
|
45
|
+
def hash_item_to_defined_job(name, defined_job_hash_in)
|
46
|
+
defined_job_hash = defined_job_hash_in.stringify_keys
|
35
47
|
# Que stores arguments as a json array. If the args we have to provide are already an
|
36
48
|
# array we can can simply pass them through. If it is a single non-nil value, then we make
|
37
49
|
# an array with one item which is that value (this includes if it is a hash). It could
|
38
50
|
# also be a single nil value.
|
39
51
|
args_array =
|
40
|
-
if
|
41
|
-
# No args were requested
|
42
|
-
[]
|
43
|
-
else
|
52
|
+
if defined_job_hash.key?("args")
|
44
53
|
args = defined_job_hash["args"]
|
45
54
|
if args.is_a?(Array)
|
46
55
|
# An array of args was requested
|
@@ -50,11 +59,14 @@ module Que
|
|
50
59
|
# be enqueued as an array of 1 item
|
51
60
|
[args]
|
52
61
|
end
|
62
|
+
else
|
63
|
+
# No args were requested
|
64
|
+
[]
|
53
65
|
end
|
54
66
|
|
55
67
|
Que::Scheduler::DefinedJob.create(
|
56
68
|
name: name,
|
57
|
-
job_class: defined_job_hash["class"] || name,
|
69
|
+
job_class: defined_job_hash["class"]&.to_s || name,
|
58
70
|
queue: defined_job_hash["queue"],
|
59
71
|
args_array: args_array,
|
60
72
|
priority: defined_job_hash["priority"],
|
@@ -69,10 +81,6 @@ module Que
|
|
69
81
|
def schedule
|
70
82
|
Schedule.schedule
|
71
83
|
end
|
72
|
-
|
73
|
-
def schedule=(value)
|
74
|
-
Schedule.schedule = value
|
75
|
-
end
|
76
84
|
end
|
77
85
|
end
|
78
86
|
end
|
@@ -16,8 +16,8 @@ module Que
|
|
16
16
|
class SchedulerJob < Que::Job
|
17
17
|
SCHEDULER_FREQUENCY = 60
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
VersionSupport.set_priority(self, 0)
|
20
|
+
VersionSupport.apply_retry_semantics(self)
|
21
21
|
|
22
22
|
def run(options = nil)
|
23
23
|
Que::Scheduler::Db.transaction do
|
@@ -27,12 +27,13 @@ module Que
|
|
27
27
|
logs = ["que-scheduler last ran at #{scheduler_job_args.last_run_time}."]
|
28
28
|
result = EnqueueingCalculator.parse(Scheduler.schedule.values, scheduler_job_args)
|
29
29
|
enqueued_jobs = enqueue_required_jobs(result, logs)
|
30
|
+
# Remove this job and schedule self again
|
31
|
+
destroy
|
30
32
|
enqueue_self_again(
|
31
33
|
scheduler_job_args, scheduler_job_args.as_time, result.job_dictionary, enqueued_jobs
|
32
34
|
)
|
33
35
|
# Only now we're sure nothing errored, log the results
|
34
36
|
logs.each { |str| ::Que.log(event: "que-scheduler".to_sym, message: str) }
|
35
|
-
destroy
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
@@ -59,7 +60,7 @@ module Que
|
|
59
60
|
|
60
61
|
def enqueue_self_again(scheduler_job_args, last_full_execution, job_dictionary, enqueued_jobs)
|
61
62
|
# Log last run...
|
62
|
-
job_id =
|
63
|
+
job_id = VersionSupport.job_attributes(self).fetch(:job_id)
|
63
64
|
Audit.append(job_id, scheduler_job_args.as_time, enqueued_jobs)
|
64
65
|
|
65
66
|
# And rerun...
|
@@ -72,7 +73,7 @@ module Que
|
|
72
73
|
)
|
73
74
|
|
74
75
|
# rubocop:disable Style/GuardClause This reads better as a conditional
|
75
|
-
unless
|
76
|
+
unless enqueued_job && VersionSupport.job_attributes(enqueued_job).fetch(:job_id)
|
76
77
|
raise "SchedulerJob could not self-schedule. Has `.enqueue` been monkey patched?"
|
77
78
|
end
|
78
79
|
# rubocop:enable Style/GuardClause
|
@@ -22,7 +22,8 @@ module Que
|
|
22
22
|
else
|
23
23
|
options = options.symbolize_keys
|
24
24
|
{
|
25
|
-
last_run_time:
|
25
|
+
last_run_time:
|
26
|
+
Que::Scheduler::TimeZone.time_zone.parse(options.fetch(:last_run_time)),
|
26
27
|
job_dictionary: options.fetch(:job_dictionary),
|
27
28
|
}
|
28
29
|
end
|
@@ -8,7 +8,6 @@ module Que
|
|
8
8
|
class << self
|
9
9
|
def check
|
10
10
|
assert_db_migrated
|
11
|
-
assert_one_scheduler_job
|
12
11
|
end
|
13
12
|
|
14
13
|
private
|
@@ -20,7 +19,7 @@ module Que
|
|
20
19
|
sync_err =
|
21
20
|
if Que::Scheduler::VersionSupport.running_synchronously? && db_version.zero?
|
22
21
|
code = Que::Scheduler::VersionSupport.running_synchronously_code?
|
23
|
-
|
22
|
+
<<~ERR_SYNC
|
24
23
|
You currently have Que to run in synchronous mode using
|
25
24
|
#{code}, so it is most likely this error
|
26
25
|
has happened during an initial migration. You should disable synchronous mode and
|
@@ -60,21 +59,6 @@ module Que
|
|
60
59
|
synchronously. This will fail as que-scheduler needs the above tables to work.
|
61
60
|
ERR
|
62
61
|
end
|
63
|
-
|
64
|
-
def assert_one_scheduler_job
|
65
|
-
schedulers = Que::Scheduler::Db.count_schedulers
|
66
|
-
return if schedulers == 1
|
67
|
-
|
68
|
-
raise(<<-ERR)
|
69
|
-
Only one #{Que::Scheduler::SchedulerJob.name} should be enqueued. #{schedulers} were found.
|
70
|
-
|
71
|
-
que-scheduler works by running a self-enqueueing version of itself that determines which
|
72
|
-
jobs should be enqueued based on the provided config. If two or more que-schedulers were
|
73
|
-
to run at once, then duplicate jobs would occur.
|
74
|
-
|
75
|
-
To resolve this problem, please remove any duplicate scheduler jobs from the que_jobs table.
|
76
|
-
ERR
|
77
|
-
end
|
78
62
|
end
|
79
63
|
end
|
80
64
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Que
|
2
|
+
module Scheduler
|
3
|
+
module TimeZone
|
4
|
+
BOTH_CONFIG_AND_TIME_DOT_ZONE_SET = <<~ERR.freeze
|
5
|
+
The que-scheduler config for time_zone has been set to a non-nil value, but
|
6
|
+
it appears to also have been set on Time.zone (possibly by Rails). Both of these
|
7
|
+
cannot be non-nil.
|
8
|
+
You should remove the time_zone config from the que-scheduler config block.
|
9
|
+
ERR
|
10
|
+
|
11
|
+
TIME_ZONE_COULD_NOT_BE_DETERMINED = <<~ERR.freeze
|
12
|
+
It appears Time.zone is nil. This prevents proper functioning of que-scheduler.
|
13
|
+
|
14
|
+
Resolving this issue depends on your application setup.
|
15
|
+
|
16
|
+
1) If you are using Rails, set the standard time_zone config
|
17
|
+
eg:
|
18
|
+
```
|
19
|
+
# In application.rb
|
20
|
+
config.time_zone = "Europe/London"
|
21
|
+
```
|
22
|
+
|
23
|
+
2) If you are not using Rails, set your time zone in the que-scheduler config:
|
24
|
+
eg:
|
25
|
+
```
|
26
|
+
Que::Scheduler.configure do |config|
|
27
|
+
config.time_zone = "Europe/London"
|
28
|
+
end
|
29
|
+
```
|
30
|
+
ERR
|
31
|
+
|
32
|
+
TIME_ZONE_CONFIG_IS_NOT_VALID = <<~ERR.freeze
|
33
|
+
The que-scheduler config for time_zone has been set to a non-nil value, but that value
|
34
|
+
does not yield a real time zone when passed to ActiveSupport::TimeZone.new
|
35
|
+
ERR
|
36
|
+
|
37
|
+
class << self
|
38
|
+
def time_zone
|
39
|
+
@time_zone ||=
|
40
|
+
begin
|
41
|
+
time_dot_zone = Time.zone
|
42
|
+
if time_dot_zone.present?
|
43
|
+
if Que::Scheduler.configuration.time_zone.present?
|
44
|
+
raise BOTH_CONFIG_AND_TIME_DOT_ZONE_SET
|
45
|
+
end
|
46
|
+
|
47
|
+
time_dot_zone
|
48
|
+
elsif Que::Scheduler.configuration.time_zone
|
49
|
+
new_tz = ActiveSupport::TimeZone.new(Que::Scheduler.configuration.time_zone)
|
50
|
+
raise TIME_ZONE_CONFIG_IS_NOT_VALID unless new_tz
|
51
|
+
|
52
|
+
new_tz
|
53
|
+
else
|
54
|
+
raise TIME_ZONE_COULD_NOT_BE_DETERMINED
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -22,14 +22,12 @@ module Que
|
|
22
22
|
type_from_job_class(job_class).present?
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
26
|
-
|
25
|
+
def active_job_loaded?
|
26
|
+
!!active_job_version
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
|
31
|
-
# https://github.com/rails/rails/pull/20056/files
|
32
|
-
active_job_version && active_job_version > Gem::Version.create("5")
|
29
|
+
def active_job_version
|
30
|
+
Gem.loaded_specs["activejob"]&.version
|
33
31
|
end
|
34
32
|
|
35
33
|
def active_job_version_supports_queues?
|
@@ -56,7 +54,7 @@ module Que
|
|
56
54
|
hash = {
|
57
55
|
::Que::Job => QueJobType,
|
58
56
|
}
|
59
|
-
hash[::ActiveJob::Base] = ActiveJobType if ToEnqueue.
|
57
|
+
hash[::ActiveJob::Base] = ActiveJobType if ToEnqueue.active_job_loaded?
|
60
58
|
hash
|
61
59
|
end
|
62
60
|
end
|
@@ -105,7 +103,13 @@ module Que
|
|
105
103
|
scheduled_at =
|
106
104
|
begin
|
107
105
|
scheduled_at_float = data[:scheduled_at]
|
108
|
-
|
106
|
+
# rubocop:disable Style/EmptyElse
|
107
|
+
if scheduled_at_float
|
108
|
+
Que::Scheduler::TimeZone.time_zone.at(scheduled_at_float)
|
109
|
+
else
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
# rubocop:enable Style/EmptyElse
|
109
113
|
end
|
110
114
|
|
111
115
|
# Rails didn't support queues for ActiveJob for a while
|
@@ -61,7 +61,11 @@ module Que
|
|
61
61
|
|
62
62
|
def zero_major?
|
63
63
|
# This is the only way to handle beta releases too
|
64
|
-
@zero_major ||=
|
64
|
+
@zero_major ||= que_version.split(".").first.to_i.zero?
|
65
|
+
end
|
66
|
+
|
67
|
+
def que_version
|
68
|
+
@que_version ||= Gem.loaded_specs["que"].version.to_s
|
65
69
|
end
|
66
70
|
|
67
71
|
private
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: que-scheduler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Harry Lascelles
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '5.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: fugit
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -90,14 +90,14 @@ dependencies:
|
|
90
90
|
requirements:
|
91
91
|
- - ">="
|
92
92
|
- !ruby/object:Gem::Version
|
93
|
-
version: '
|
93
|
+
version: '5.0'
|
94
94
|
type: :development
|
95
95
|
prerelease: false
|
96
96
|
version_requirements: !ruby/object:Gem::Requirement
|
97
97
|
requirements:
|
98
98
|
- - ">="
|
99
99
|
- !ruby/object:Gem::Version
|
100
|
-
version: '
|
100
|
+
version: '5.0'
|
101
101
|
- !ruby/object:Gem::Dependency
|
102
102
|
name: appraisal
|
103
103
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,6 +112,20 @@ dependencies:
|
|
112
112
|
- - ">="
|
113
113
|
- !ruby/object:Gem::Version
|
114
114
|
version: '0'
|
115
|
+
- !ruby/object:Gem::Dependency
|
116
|
+
name: climate_control
|
117
|
+
requirement: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
type: :development
|
123
|
+
prerelease: false
|
124
|
+
version_requirements: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
115
129
|
- !ruby/object:Gem::Dependency
|
116
130
|
name: combustion
|
117
131
|
requirement: !ruby/object:Gem::Requirement
|
@@ -244,14 +258,14 @@ dependencies:
|
|
244
258
|
requirements:
|
245
259
|
- - '='
|
246
260
|
- !ruby/object:Gem::Version
|
247
|
-
version:
|
261
|
+
version: 1.5.2
|
248
262
|
type: :development
|
249
263
|
prerelease: false
|
250
264
|
version_requirements: !ruby/object:Gem::Requirement
|
251
265
|
requirements:
|
252
266
|
- - '='
|
253
267
|
- !ruby/object:Gem::Version
|
254
|
-
version:
|
268
|
+
version: 1.5.2
|
255
269
|
- !ruby/object:Gem::Dependency
|
256
270
|
name: rubocop-rspec
|
257
271
|
requirement: !ruby/object:Gem::Requirement
|
@@ -319,7 +333,7 @@ files:
|
|
319
333
|
- lib/que-scheduler.rb
|
320
334
|
- lib/que/scheduler.rb
|
321
335
|
- lib/que/scheduler/audit.rb
|
322
|
-
- lib/que/scheduler/
|
336
|
+
- lib/que/scheduler/configuration.rb
|
323
337
|
- lib/que/scheduler/db.rb
|
324
338
|
- lib/que/scheduler/defined_job.rb
|
325
339
|
- lib/que/scheduler/enqueueing_calculator.rb
|
@@ -335,10 +349,13 @@ files:
|
|
335
349
|
- lib/que/scheduler/migrations/4/up.sql
|
336
350
|
- lib/que/scheduler/migrations/5/down.sql
|
337
351
|
- lib/que/scheduler/migrations/5/up.sql
|
352
|
+
- lib/que/scheduler/migrations/6/down.sql
|
353
|
+
- lib/que/scheduler/migrations/6/up.sql
|
338
354
|
- lib/que/scheduler/schedule.rb
|
339
355
|
- lib/que/scheduler/scheduler_job.rb
|
340
356
|
- lib/que/scheduler/scheduler_job_args.rb
|
341
357
|
- lib/que/scheduler/state_checks.rb
|
358
|
+
- lib/que/scheduler/time_zone.rb
|
342
359
|
- lib/que/scheduler/to_enqueue.rb
|
343
360
|
- lib/que/scheduler/version.rb
|
344
361
|
- lib/que/scheduler/version_support.rb
|
@@ -359,7 +376,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
359
376
|
requirements:
|
360
377
|
- - ">="
|
361
378
|
- !ruby/object:Gem::Version
|
362
|
-
version: '
|
379
|
+
version: '2.5'
|
363
380
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
364
381
|
requirements:
|
365
382
|
- - ">="
|
data/lib/que/scheduler/config.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
require "que"
|
2
|
-
require_relative "version_support"
|
3
|
-
|
4
|
-
module Que
|
5
|
-
module Scheduler
|
6
|
-
class << self
|
7
|
-
attr_accessor :configuration
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.configure
|
11
|
-
self.configuration ||= Configuration.new
|
12
|
-
yield(configuration)
|
13
|
-
end
|
14
|
-
|
15
|
-
class Configuration
|
16
|
-
attr_accessor :schedule_location
|
17
|
-
attr_accessor :transaction_adapter
|
18
|
-
attr_accessor :que_scheduler_queue
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
Que::Scheduler.configure do |config|
|
24
|
-
config.schedule_location = ENV.fetch("QUE_SCHEDULER_CONFIG_LOCATION", "config/que_schedule.yml")
|
25
|
-
config.transaction_adapter = ::Que.method(:transaction)
|
26
|
-
config.que_scheduler_queue = Que::Scheduler::VersionSupport.default_scheduler_queue
|
27
|
-
end
|