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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ba02202915db229bcbd1c2e859f29299803507dbf61bd460008400abca3611c
4
- data.tar.gz: 6293d7b6e6766d0e75fe65df01850f356b44b030c8b8ae539eb4c71059d9d15d
3
+ metadata.gz: a75db11d923c140204bd92360916e4cacaac5531fc25470616a4d558dde22dd3
4
+ data.tar.gz: ba08caa1a8bf8a87532da3fa5cbfc8b720784e88354ab74b240c5d724c46fb07
5
5
  SHA512:
6
- metadata.gz: d8d18550867d7d54cfb5c03aaa68876d423876a870b972cde0fbc4e8399fb616d327ef0410ebbc8e3d9021a34d73a960774eabb808f2b33a526e11ea2fb579fe
7
- data.tar.gz: bfc0e4be1f64d2b070dacb0863cc710ce13cf58cb30924fcf9f301d2e535be4ef9530740949bdb5abb90c0173924e71f7f151e4622405caf8c14a9d7d6f0469d
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: 5)
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 with
40
- `Que::Scheduler.schedule = some_hash`.
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 an initializer. The default is given below.
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('QUE_SCHEDULER_CONFIG_LOCATION', 'config/que_schedule.yml')
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
- # Specify a transaction block adapter. By default, que-scheduler uses the one supplied by que.
146
- # However, if, for example you rely on listeners to ActiveRecord's exact `transaction` method, or
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. To run in all the migrations required
164
- up to a number, just migrate to that number with one line, and it will perform all the intermediary steps.
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: 5)
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
- ## Built in optional job for audit clear down
188
-
189
- que-scheduler comes with the `QueSchedulerAuditClearDownJob` job built in that you can optionally
190
- schedule to clear down audit rows if you don't need to retain them indefinitely. You should add this
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
- For example:
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 it will check before performing any operations that
218
- there is only one of itself present.
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.4.0.
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
- * @JackDanger
326
+ * @papodaca
@@ -1,6 +1,7 @@
1
1
  require "que/scheduler/version"
2
2
  require "que/scheduler/version_support"
3
- require "que/scheduler/config"
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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "config"
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.active_job_sufficient_version? &&
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 <<-ERR
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
- <<-SQL
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,7 @@
1
+ DROP TRIGGER que_scheduler_prevent_job_deletion_trigger ON que_jobs;
2
+
3
+ DROP FUNCTION que_scheduler_prevent_job_deletion();
4
+
5
+ DROP FUNCTION que_scheduler_check_job_exists();
6
+
7
+ DROP INDEX que_scheduler_job_in_que_jobs_unique_index;
@@ -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
- location = Que::Scheduler.configuration.schedule_location
11
- from_file(location)
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
- [name, hash_item_to_defined_job(name, defined_job_hash)]
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, defined_job_hash)
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 !defined_job_hash.key?("args")
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
- Que::Scheduler::VersionSupport.set_priority(self, 0)
20
- Que::Scheduler::VersionSupport.apply_retry_semantics(self)
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 = Que::Scheduler::VersionSupport.job_attributes(self).fetch(: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 Que::Scheduler::VersionSupport.job_attributes(enqueued_job).fetch(:job_id)
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: Time.zone.parse(options.fetch(: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
- <<-ERR_SYNC
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 active_job_version
26
- Gem.loaded_specs["activejob"]&.version
25
+ def active_job_loaded?
26
+ !!active_job_version
27
27
  end
28
28
 
29
- def active_job_sufficient_version?
30
- # ActiveJob 4.x does not support job_ids correctly
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.active_job_sufficient_version?
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
- scheduled_at_float ? Time.zone.at(scheduled_at_float) : nil
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
@@ -1,5 +1,5 @@
1
1
  module Que
2
2
  module Scheduler
3
- VERSION = "3.4.3".freeze
3
+ VERSION = "4.1.0".freeze
4
4
  end
5
5
  end
@@ -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 ||= Gem.loaded_specs["que"].version.to_s.split(".").first.to_i.zero?
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: 3.4.3
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: 2020-10-28 00:00:00.000000000 Z
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: '4.0'
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: '4.0'
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: '4.0'
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: '4.0'
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: 0.84.0
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: 0.84.0
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/config.rb
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: '0'
379
+ version: '2.5'
363
380
  required_rubygems_version: !ruby/object:Gem::Requirement
364
381
  requirements:
365
382
  - - ">="
@@ -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