sidekiq-scheduler 2.1.9 → 2.1.10

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
  SHA1:
3
- metadata.gz: 310c3a0ed3c3976eb6585432e0b2bd00ddb4ddb8
4
- data.tar.gz: ee996ad32bfaacb0f3aa77a7f3073a3a8ad4d9f4
3
+ metadata.gz: a3f7cb5ee802d2e3b5c89b308fbcaff612911217
4
+ data.tar.gz: e6b488b10334b3af01c9d2521e31ec3c53f0ef20
5
5
  SHA512:
6
- metadata.gz: 629bdc5d21f6907a7427356d3b78d1a253587aea9b7f3528ba92f2cc1f3f2b01116eeddb36830a1bed3341e7a9f6d192d94ba1ac3e9c66bf80663a4f5d31fc1c
7
- data.tar.gz: b2a7113238972d104d65f19d465ead5846e157696dee0c77f51000ba4dc751ca6d597566e44824f6012e722d770a634fb9d655d47dd11fafdbb3eb5858010e7a
6
+ metadata.gz: b56413d0c141f2ae15bfacb255a8eed2550b6b0f899703f5fd08d67539794878e411d9a5a48086f4fd9d7f542f6b78fe9a016b7edf32a78819b93c7860ecf2a2
7
+ data.tar.gz: 6b8524661830f24e9233a95ec94a18ad31eac1f0880a63a3bc48f728e802f8f5ffe79437bfd5d17bdc3ec07a79d142b0d991b33a5a6363f79a4e6f1c387ee2c2
data/README.md CHANGED
@@ -94,6 +94,7 @@ Available options are:
94
94
 
95
95
  ``` yaml
96
96
  :dynamic: <if true the schedule can be modified in runtime [false by default]>
97
+ :dynamic_every: <if dynamic is true, the schedule is reloaded every interval [5s by default]>
97
98
  :enabled: <enables scheduler if true [true by default]>
98
99
  :scheduler:
99
100
  :listened_queues_only: <push jobs whose queue is being listened by sidekiq [false by default]>
@@ -244,7 +245,7 @@ Sidekiq.set_schedule('heartbeat', { 'every' => ['1m'], 'class' => 'HeartbeatWork
244
245
 
245
246
  If the schedule did not exist it will be created, if it existed it will be updated.
246
247
 
247
- When `:dynamic` flag is set to `true`, schedule changes are loaded every 5 seconds.
248
+ When `:dynamic` flag is set to `true`, schedule changes are loaded every 5 seconds. Use the `:dynamic_every` flag for a different interval.
248
249
 
249
250
  ``` yaml
250
251
  # config/sidekiq.yml
@@ -3,6 +3,7 @@ require 'tilt/erb'
3
3
 
4
4
  require_relative 'sidekiq-scheduler/version'
5
5
  require_relative 'sidekiq-scheduler/manager'
6
+ require_relative 'sidekiq-scheduler/redis_manager'
6
7
 
7
8
  Sidekiq.configure_server do |config|
8
9
 
@@ -10,6 +11,9 @@ Sidekiq.configure_server do |config|
10
11
  dynamic = Sidekiq::Scheduler.dynamic
11
12
  dynamic = dynamic.nil? ? config.options.fetch(:dynamic, false) : dynamic
12
13
 
14
+ dynamic_every = Sidekiq::Scheduler.dynamic_every
15
+ dynamic_every = dynamic_every.nil? ? config.options.fetch(:dynamic_every, '5s') : dynamic_every
16
+
13
17
  enabled = Sidekiq::Scheduler.enabled
14
18
  enabled = enabled.nil? ? config.options.fetch(:enabled, true) : enabled
15
19
 
@@ -22,14 +26,15 @@ Sidekiq.configure_server do |config|
22
26
  schedule ||= config.options[:schedule] || {}
23
27
 
24
28
  scheduler_options = {
25
- dynamic: dynamic,
26
- enabled: enabled,
27
- schedule: schedule,
29
+ dynamic: dynamic,
30
+ dynamic_every: dynamic_every,
31
+ enabled: enabled,
32
+ schedule: schedule,
28
33
  listened_queues_only: listened_queues_only
29
34
  }
30
35
 
31
36
  # schedules_changed's type was changed from SET to ZSET, so we remove old versions at startup
32
- Sidekiq.redis { |r| r.del(:schedules_changed) unless r.type(:schedules_changed) == 'zset' }
37
+ SidekiqScheduler::RedisManager.clean_schedules_changed
33
38
 
34
39
  schedule_manager = SidekiqScheduler::Manager.new(scheduler_options)
35
40
  config.options[:schedule_manager] = schedule_manager
@@ -3,6 +3,7 @@ begin
3
3
  rescue LoadError
4
4
  require 'sidekiq/web_helpers'
5
5
  end
6
+ require 'sidekiq-scheduler/redis_manager'
6
7
 
7
8
  module SidekiqScheduler
8
9
  class JobPresenter
@@ -19,7 +20,7 @@ module SidekiqScheduler
19
20
  #
20
21
  # @return [String] with the job's next time
21
22
  def next_time
22
- execution_time = Sidekiq.redis { |r| r.hget(Sidekiq::Scheduler.next_times_key, name) }
23
+ execution_time = SidekiqScheduler::RedisManager.get_job_next_time(name)
23
24
 
24
25
  relative_time(Time.parse(execution_time)) if execution_time
25
26
  end
@@ -28,7 +29,7 @@ module SidekiqScheduler
28
29
  #
29
30
  # @return [String] with the job's last time
30
31
  def last_time
31
- execution_time = Sidekiq.redis { |r| r.hget(Sidekiq::Scheduler.last_times_key, name) }
32
+ execution_time = SidekiqScheduler::RedisManager.get_job_last_time(name)
32
33
 
33
34
  relative_time(Time.parse(execution_time)) if execution_time
34
35
  end
@@ -17,6 +17,7 @@ module SidekiqScheduler
17
17
  def initialize(options)
18
18
  Sidekiq::Scheduler.enabled = options[:enabled]
19
19
  Sidekiq::Scheduler.dynamic = options[:dynamic]
20
+ Sidekiq::Scheduler.dynamic_every = options[:dynamic_every]
20
21
  Sidekiq::Scheduler.listened_queues_only = options[:listened_queues_only]
21
22
  Sidekiq.schedule = options[:schedule] if Sidekiq::Scheduler.enabled
22
23
  end
@@ -0,0 +1,212 @@
1
+ module SidekiqScheduler
2
+ module RedisManager
3
+
4
+ REGISTERED_JOBS_THRESHOLD_IN_SECONDS = 24 * 60 * 60
5
+
6
+ # Returns the schedule of a given job
7
+ #
8
+ # @param [String] name The name of the job
9
+ #
10
+ # @return [String] schedule in JSON format
11
+ def self.get_job_schedule(name)
12
+ hget(:schedules, name)
13
+ end
14
+
15
+ # Returns the state of a given job
16
+ #
17
+ # @param [String] name The name of the job
18
+ #
19
+ # @return [String] state in JSON format
20
+ def self.get_job_state(name)
21
+ hget(schedules_state_key, name)
22
+ end
23
+
24
+ # Returns the next execution time for a given job
25
+ #
26
+ # @param [String] name The name of the job
27
+ #
28
+ # @return [String] next time the job has to be executed
29
+ def self.get_job_next_time(name)
30
+ hget(next_times_key, name)
31
+ end
32
+
33
+ # Returns the last execution time of a given job
34
+ #
35
+ # @param [String] name The name of the job
36
+ #
37
+ # @return [String] last time the job was executed
38
+ def self.get_job_last_time(name)
39
+ hget(last_times_key, name)
40
+ end
41
+
42
+ # Sets the schedule for a given job
43
+ #
44
+ # @param [String] name The name of the job
45
+ # @param [Hash] config The new schedule for the job
46
+ def self.set_job_schedule(name, config)
47
+ hset(:schedules, name, JSON.generate(config))
48
+ end
49
+
50
+ # Sets the state for a given job
51
+ #
52
+ # @param [String] name The name of the job
53
+ # @param [Hash] state The new state for the job
54
+ def self.set_job_state(name, state)
55
+ hset(schedules_state_key, name, JSON.generate(state))
56
+ end
57
+
58
+ # Sets the next execution time for a given job
59
+ #
60
+ # @param [String] name The name of the job
61
+ # @param [String] next_time The next time the job has to be executed
62
+ def self.set_job_next_time(name, next_time)
63
+ hset(next_times_key, name, next_time)
64
+ end
65
+
66
+ # Sets the last execution time for a given job
67
+ #
68
+ # @param [String] name The name of the job
69
+ # @param [String] last_time The last time the job was executed
70
+ def self.set_job_last_time(name, last_time)
71
+ hset(last_times_key, name, last_time)
72
+ end
73
+
74
+ # Removes the schedule for a given job
75
+ #
76
+ # @param [String] name The name of the job
77
+ def self.remove_job_schedule(name)
78
+ hdel(:schedules, name)
79
+ end
80
+
81
+ # Removes the next execution time for a given job
82
+ #
83
+ # @param [String] name The name of the job
84
+ def self.remove_job_next_time(name)
85
+ hdel(next_times_key, name)
86
+ end
87
+
88
+ # Returns the schedules of all the jobs
89
+ #
90
+ # @return [Hash] hash with all the job schedules
91
+ def self.get_all_schedules
92
+ Sidekiq.redis { |r| r.hgetall(:schedules) }
93
+ end
94
+
95
+ # Returns boolean value that indicates if the schedules value exists
96
+ #
97
+ # @return [Boolean] true if the schedules key is set, false otherwise
98
+ def self.schedule_exist?
99
+ Sidekiq.redis { |r| r.exists(:schedules) }
100
+ end
101
+
102
+ # Returns all the schedule changes for a given time range.
103
+ #
104
+ # @param [Float] from The minimum value in the range
105
+ # @param [Float] to The maximum value in the range
106
+ #
107
+ # @return [Array] array with all the changed job names
108
+ def self.get_schedule_changes(from, to)
109
+ Sidekiq.redis { |r| r.zrangebyscore(:schedules_changed, from, "(#{to}") }
110
+ end
111
+
112
+ # Register a schedule change for a given job
113
+ #
114
+ # @param [String] name The name of the job
115
+ def self.add_schedule_change(name)
116
+ Sidekiq.redis { |r| r.zadd(:schedules_changed, Time.now.to_f, name) }
117
+ end
118
+
119
+ # Remove all the schedule changes records
120
+ def self.clean_schedules_changed
121
+ Sidekiq.redis { |r| r.del(:schedules_changed) unless r.type(:schedules_changed) == 'zset' }
122
+ end
123
+
124
+ # Removes a queued job instance
125
+ #
126
+ # @param [String] job_name The name of the job
127
+ # @param [Time] time The time at which the job was cleared by the scheduler
128
+ #
129
+ # @return [Boolean] true if the job was registered, false otherwise
130
+ def self.register_job_instance(job_name, time)
131
+ job_key = pushed_job_key(job_name)
132
+ registered, _ = Sidekiq.redis do |r|
133
+ r.pipelined do
134
+ r.zadd(job_key, time.to_i, time.to_i)
135
+ r.expire(job_key, REGISTERED_JOBS_THRESHOLD_IN_SECONDS)
136
+ end
137
+ end
138
+
139
+ registered
140
+ end
141
+
142
+ # Removes instances of the job older than 24 hours
143
+ #
144
+ # @param [String] job_name The name of the job
145
+ def self.remove_elder_job_instances(job_name)
146
+ seconds_ago = Time.now.to_i - REGISTERED_JOBS_THRESHOLD_IN_SECONDS
147
+
148
+ Sidekiq.redis do |r|
149
+ r.zremrangebyscore(pushed_job_key(job_name), 0, seconds_ago)
150
+ end
151
+ end
152
+
153
+ # Returns the key of the Redis sorted set used to store job enqueues
154
+ #
155
+ # @param [String] job_name The name of the job
156
+ #
157
+ # @return [String] the pushed job key
158
+ def self.pushed_job_key(job_name)
159
+ "sidekiq-scheduler:pushed:#{job_name}"
160
+ end
161
+
162
+ # Returns the key of the Redis hash for job's execution times hash
163
+ #
164
+ # @return [String] with the key
165
+ def self.next_times_key
166
+ 'sidekiq-scheduler:next_times'
167
+ end
168
+
169
+ # Returns the key of the Redis hash for job's last execution times hash
170
+ #
171
+ # @return [String] with the key
172
+ def self.last_times_key
173
+ 'sidekiq-scheduler:last_times'
174
+ end
175
+
176
+ # Returns the Redis's key for saving schedule states.
177
+ #
178
+ # @return [String] with the key
179
+ def self.schedules_state_key
180
+ 'sidekiq-scheduler:states'
181
+ end
182
+
183
+ private
184
+
185
+ # Returns the value of a Redis stored hash field
186
+ #
187
+ # @param [String] hash_key The key name of the hash
188
+ # @param [String] field_key The key name of the field
189
+ #
190
+ # @return [String]
191
+ def self.hget(hash_key, field_key)
192
+ Sidekiq.redis { |r| r.hget(hash_key, field_key) }
193
+ end
194
+
195
+ # Sets the value of a Redis stored hash field
196
+ #
197
+ # @param [String] hash_key The key name of the hash
198
+ # @param [String] field_key The key name of the field
199
+ # @param [String] value The new value name for the field
200
+ def self.hset(hash_key, field_key, value)
201
+ Sidekiq.redis { |r| r.hset(hash_key, field_key, value) }
202
+ end
203
+
204
+ # Removes the value of a Redis stored hash field
205
+ #
206
+ # @param [String] hash_key The key name of the hash
207
+ # @param [String] field_key The key name of the field
208
+ def self.hdel(hash_key, field_key)
209
+ Sidekiq.redis { |r| r.hdel(hash_key, field_key) }
210
+ end
211
+ end
212
+ end
@@ -1,6 +1,7 @@
1
1
  require 'json'
2
2
 
3
3
  require 'sidekiq-scheduler/utils'
4
+ require_relative 'redis_manager'
4
5
 
5
6
  module SidekiqScheduler
6
7
  module Schedule
@@ -71,7 +72,7 @@ module SidekiqScheduler
71
72
  if name.nil?
72
73
  get_all_schedules
73
74
  else
74
- encoded_schedule = Sidekiq.redis { |r| r.hget(:schedules, name) }
75
+ encoded_schedule = SidekiqScheduler::RedisManager.get_job_schedule(name)
75
76
  encoded_schedule.nil? ? nil : JSON.parse(encoded_schedule)
76
77
  end
77
78
  end
@@ -80,8 +81,8 @@ module SidekiqScheduler
80
81
  def get_all_schedules
81
82
  schedules = {}
82
83
 
83
- if Sidekiq.redis { |r| r.exists(:schedules) }
84
- Sidekiq.redis { |r| r.hgetall(:schedules) }.tap do |h|
84
+ if SidekiqScheduler::RedisManager.schedule_exist?
85
+ SidekiqScheduler::RedisManager.get_all_schedules.tap do |h|
85
86
  h.each do |name, config|
86
87
  schedules[name] = JSON.parse(config)
87
88
  end
@@ -103,16 +104,16 @@ module SidekiqScheduler
103
104
  def set_schedule(name, config)
104
105
  existing_config = get_schedule(name)
105
106
  unless existing_config && existing_config == config
106
- Sidekiq.redis { |r| r.hset(:schedules, name, JSON.generate(config)) }
107
- Sidekiq.redis { |r| r.zadd(:schedules_changed, Time.now.to_f, name) }
107
+ SidekiqScheduler::RedisManager.set_job_schedule(name, config)
108
+ SidekiqScheduler::RedisManager.add_schedule_change(name)
108
109
  end
109
110
  config
110
111
  end
111
112
 
112
113
  # remove a given schedule by name
113
114
  def remove_schedule(name)
114
- Sidekiq.redis { |r| r.hdel(:schedules, name) }
115
- Sidekiq.redis { |r| r.zadd(:schedules_changed, Time.now.to_f, name) }
115
+ SidekiqScheduler::RedisManager.remove_job_schedule(name)
116
+ SidekiqScheduler::RedisManager.add_schedule_change(name)
116
117
  end
117
118
 
118
119
  private
@@ -1,5 +1,5 @@
1
1
  module SidekiqScheduler
2
2
 
3
- VERSION = '2.1.9'
3
+ VERSION = '2.1.10'
4
4
 
5
5
  end
@@ -3,13 +3,13 @@ require 'thwait'
3
3
  require 'sidekiq/util'
4
4
  require 'sidekiq-scheduler/manager'
5
5
  require 'sidekiq-scheduler/rufus_utils'
6
+ require_relative '../sidekiq-scheduler/redis_manager'
6
7
  require 'json'
7
8
 
8
9
  module Sidekiq
9
10
  class Scheduler
10
11
  extend Sidekiq::Util
11
12
 
12
- REGISTERED_JOBS_THRESHOLD_IN_SECONDS = 24 * 60 * 60
13
13
  RUFUS_METADATA_KEYS = %w(description at cron every in interval enabled)
14
14
 
15
15
  # We expect rufus jobs to have #params
@@ -27,6 +27,9 @@ module Sidekiq
27
27
  # Set to update the schedule in runtime in a given time period.
28
28
  attr_accessor :dynamic
29
29
 
30
+ # Set to update the schedule in runtime dynamically per this period.
31
+ attr_accessor :dynamic_every
32
+
30
33
  # Set to schedule jobs only when will be pushed to queues listened by sidekiq
31
34
  attr_accessor :listened_queues_only
32
35
 
@@ -55,7 +58,7 @@ module Sidekiq
55
58
  if dynamic
56
59
  Sidekiq.reload_schedule!
57
60
  @current_changed_score = Time.now.to_f
58
- rufus_scheduler.every('5s') do
61
+ rufus_scheduler.every(dynamic_every) do
59
62
  update_schedule
60
63
  end
61
64
  end
@@ -137,8 +140,10 @@ module Sidekiq
137
140
  # @param [String] name The job's name
138
141
  # @param [Time] next_time The job's next time execution
139
142
  def update_job_next_time(name, next_time)
140
- Sidekiq.redis do |r|
141
- next_time ? r.hset(next_times_key, name, next_time) : r.hdel(next_times_key, name)
143
+ if next_time
144
+ SidekiqScheduler::RedisManager.set_job_next_time(name, next_time)
145
+ else
146
+ SidekiqScheduler::RedisManager.remove_job_next_time(name)
142
147
  end
143
148
  end
144
149
 
@@ -147,7 +152,7 @@ module Sidekiq
147
152
  # @param [String] name The job's name
148
153
  # @param [Time] last_time The job's last execution time
149
154
  def update_job_last_time(name, last_time)
150
- Sidekiq.redis { |r| r.hset(last_times_key, name, last_time) } if last_time
155
+ SidekiqScheduler::RedisManager.set_job_last_time(name, last_time) if last_time
151
156
  end
152
157
 
153
158
  # Returns true if the given schedule config hash matches the current
@@ -215,9 +220,7 @@ module Sidekiq
215
220
 
216
221
  def update_schedule
217
222
  last_changed_score, @current_changed_score = @current_changed_score, Time.now.to_f
218
- schedule_changes = Sidekiq.redis do |r|
219
- r.zrangebyscore :schedules_changed, last_changed_score, "(#{@current_changed_score}"
220
- end
223
+ schedule_changes = SidekiqScheduler::RedisManager.get_schedule_changes(last_changed_score, @current_changed_score)
221
224
 
222
225
  if schedule_changes.size > 0
223
226
  logger.info 'Updating schedule'
@@ -318,52 +321,11 @@ module Sidekiq
318
321
  #
319
322
  # @return [Boolean] true if the job was registered, false when otherwise
320
323
  def register_job_instance(job_name, time)
321
- pushed_job_key = pushed_job_key(job_name)
322
-
323
- registered, _ = Sidekiq.redis do |r|
324
- r.pipelined do
325
- r.zadd(pushed_job_key, time.to_i, time.to_i)
326
- r.expire(pushed_job_key, REGISTERED_JOBS_THRESHOLD_IN_SECONDS)
327
- end
328
- end
329
-
330
- registered
324
+ SidekiqScheduler::RedisManager.register_job_instance(job_name, time)
331
325
  end
332
326
 
333
327
  def remove_elder_job_instances(job_name)
334
- Sidekiq.redis do |r|
335
- r.zremrangebyscore(pushed_job_key(job_name), 0, Time.now.to_i - REGISTERED_JOBS_THRESHOLD_IN_SECONDS)
336
- end
337
- end
338
-
339
- # Returns the key of the Redis sorted set used to store job enqueues
340
- #
341
- # @param [String] job_name The name of the job
342
- #
343
- # @return [String]
344
- def pushed_job_key(job_name)
345
- "sidekiq-scheduler:pushed:#{job_name}"
346
- end
347
-
348
- # Returns the key of the Redis hash for job's execution times hash
349
- #
350
- # @return [String] with the key
351
- def next_times_key
352
- 'sidekiq-scheduler:next_times'
353
- end
354
-
355
- # Returns the key of the Redis hash for job's last execution times hash
356
- #
357
- # @return [String] with the key
358
- def last_times_key
359
- 'sidekiq-scheduler:last_times'
360
- end
361
-
362
- # Returns the Redis's key for saving schedule states.
363
- #
364
- # @return [String] with the key
365
- def schedules_state_key
366
- 'sidekiq-scheduler:states'
328
+ SidekiqScheduler::RedisManager.remove_elder_job_instances(job_name)
367
329
  end
368
330
 
369
331
  def job_enabled?(name)
@@ -405,7 +367,7 @@ module Sidekiq
405
367
  # @param name [String] with the schedule's name
406
368
  # @return [Hash] with the schedule's state
407
369
  def schedule_state(name)
408
- state = Sidekiq.redis { |r| r.hget(schedules_state_key, name) }
370
+ state = SidekiqScheduler::RedisManager.get_job_state(name)
409
371
 
410
372
  state ? JSON.parse(state) : {}
411
373
  end
@@ -415,7 +377,7 @@ module Sidekiq
415
377
  # @param name [String] with the schedule's name
416
378
  # @param name [Hash] with the schedule's state
417
379
  def set_schedule_state(name, state)
418
- Sidekiq.redis { |r| r.hset(schedules_state_key, name, JSON.generate(state)) }
380
+ SidekiqScheduler::RedisManager.set_job_state(name, state)
419
381
  end
420
382
 
421
383
  # Adds a Hash with schedule metadata as the last argument to call the worker.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.9
4
+ version: 2.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Morton Jonuschat
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-08-31 00:00:00.000000000 Z
12
+ date: 2017-10-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sidekiq
@@ -29,16 +29,22 @@ dependencies:
29
29
  name: redis
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
34
  version: '3'
35
+ - - "<"
36
+ - !ruby/object:Gem::Version
37
+ version: '5'
35
38
  type: :runtime
36
39
  prerelease: false
37
40
  version_requirements: !ruby/object:Gem::Requirement
38
41
  requirements:
39
- - - "~>"
42
+ - - ">="
40
43
  - !ruby/object:Gem::Version
41
44
  version: '3'
45
+ - - "<"
46
+ - !ruby/object:Gem::Version
47
+ version: '5'
42
48
  - !ruby/object:Gem::Dependency
43
49
  name: rufus-scheduler
44
50
  requirement: !ruby/object:Gem::Requirement
@@ -235,6 +241,7 @@ files:
235
241
  - lib/sidekiq-scheduler.rb
236
242
  - lib/sidekiq-scheduler/job_presenter.rb
237
243
  - lib/sidekiq-scheduler/manager.rb
244
+ - lib/sidekiq-scheduler/redis_manager.rb
238
245
  - lib/sidekiq-scheduler/rufus_utils.rb
239
246
  - lib/sidekiq-scheduler/schedule.rb
240
247
  - lib/sidekiq-scheduler/utils.rb