sidekiq-cron 1.6.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -7
- data/README.md +16 -8
- data/lib/sidekiq/cron/job.rb +102 -89
- data/lib/sidekiq/cron/launcher.rb +7 -9
- data/lib/sidekiq/cron/poller.rb +9 -12
- data/lib/sidekiq/cron/schedule_loader.rb +12 -4
- data/lib/sidekiq/cron/support.rb +0 -1
- data/lib/sidekiq/cron/version.rb +1 -1
- data/lib/sidekiq/cron/web_extension.rb +6 -9
- data/lib/sidekiq/options.rb +18 -0
- data/sidekiq-cron.gemspec +5 -7
- data/test/integration/performance_test.rb +1 -1
- data/test/test_helper.rb +1 -0
- data/test/unit/fixtures/schedule_array.yml +13 -0
- data/test/unit/fixtures/schedule_hash.yml +12 -0
- data/test/unit/fixtures/schedule_string.yml +1 -0
- data/test/unit/job_test.rb +114 -20
- data/test/unit/poller_test.rb +6 -6
- data/test/unit/schedule_loader_test.rb +45 -0
- data/test/unit/web_extension_test.rb +2 -2
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d16f511a8148eadb1246263f53b596b643f9a653e0fb7877e8eaa6e0d0f2f57c
|
4
|
+
data.tar.gz: 874babda0f4da8f7928b69a226b967d79d59eacc79c101d0e087f064d31e6423
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c23cfaf18069f8e85b777807e2ceaab25d7a0d58983541044e84791e5f484998d00b5042f1f25222f050f7900d182c371227c03270cd66243c440d02cf98065b
|
7
|
+
data.tar.gz: 4e809ad13f7cde7f02a3e3ea44c6500e3e430c95e8ae12136b7625bc8ab7a452748e3769adbbef619d033a4346800693b329c40c1f4836594e8c242e4089737f
|
data/CHANGELOG.md
CHANGED
@@ -2,10 +2,17 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## 1.7.0
|
6
|
+
|
7
|
+
- Enable to use cron notation in natural language (ie `every 30 minutes`) (https://github.com/ondrejbartas/sidekiq-cron/pull/312)
|
8
|
+
- Fix `date_as_argument` feature to add timestamp argument at every cron job execution (https://github.com/ondrejbartas/sidekiq-cron/pull/329)
|
9
|
+
- Introduce `Sidekiq::Options` to centralize reading/writing options from different Sidekiq versions (https://github.com/ondrejbartas/sidekiq-cron/pull/341)
|
10
|
+
- Make auto schedule loading compatible with Array format (https://github.com/ondrejbartas/sidekiq-cron/pull/345)
|
11
|
+
|
5
12
|
## 1.6.0
|
6
13
|
|
7
|
-
- Adds support for auto-loading the config/schedule.yml file (https://github.com/ondrejbartas/sidekiq-cron/pull/337)
|
8
|
-
- Fix Sidekiq.options deprecation warning (https://github.com/ondrejbartas/sidekiq-cron/pull/338)
|
14
|
+
- Adds support for auto-loading the `config/schedule.yml` file (https://github.com/ondrejbartas/sidekiq-cron/pull/337)
|
15
|
+
- Fix `Sidekiq.options` deprecation warning (https://github.com/ondrejbartas/sidekiq-cron/pull/338)
|
9
16
|
|
10
17
|
## 1.5.1
|
11
18
|
|
@@ -30,7 +37,6 @@ All notable changes to this project will be documented in this file.
|
|
30
37
|
|
31
38
|
- Add confirmation dialog when enquing jobs from UI
|
32
39
|
- Start to support Sidekiq `average_scheduled_poll_interval` option (replaced `poll_interval`)
|
33
|
-
- Enable to use latest fugit to parse cron notation alowing use of natural language (ie `"every 30 minutes"`)
|
34
40
|
- Fix deprecation warning for Redis 4.6.x
|
35
41
|
- Fix different response from Redis#exists in different Redis versions
|
36
42
|
- All PRs:
|
@@ -52,7 +58,7 @@ All notable changes to this project will be documented in this file.
|
|
52
58
|
|
53
59
|
- Updated readme
|
54
60
|
- Fix unit tests - changed argument error when getting invalid cron format
|
55
|
-
- When fallbacking old job enqueued time use `Time.parse` without format (so
|
61
|
+
- When fallbacking old job enqueued time use `Time.parse` without format (so Ruby can decide best method to parse it)
|
56
62
|
- Add option `date_as_argument` which will add to your job arguments on last place `Time.now.to_f` when it was eneuqued
|
57
63
|
- Add option `description` which will allow you to add notes to your jobs so in web view you can see it
|
58
64
|
- Fixed translations
|
@@ -76,8 +82,8 @@ All notable changes to this project will be documented in this file.
|
|
76
82
|
- Fix poller to enqueu all jobs in poll start time
|
77
83
|
- Add performance test for enqueue of jobs (10 000 jobs in less than 19s)
|
78
84
|
- Fix problem with default queue
|
79
|
-
- Remove redis-namespace from dependencies
|
80
|
-
- Update
|
85
|
+
- Remove `redis-namespace` from dependencies
|
86
|
+
- Update Ruby versions in Travis
|
81
87
|
|
82
88
|
## 0.5.0
|
83
89
|
|
@@ -89,7 +95,7 @@ All notable changes to this project will be documented in this file.
|
|
89
95
|
- Add Russian locale
|
90
96
|
- User Rack.env in tests
|
91
97
|
- Faster enqueue of jobs
|
92
|
-
- Permit to use ActiveJob::Base.queue_name_delimiter
|
98
|
+
- Permit to use `ActiveJob::Base.queue_name_delimiter`
|
93
99
|
- Fix problem with multiple times enqueue #84
|
94
100
|
- Fix problem with enqueue of unknown class
|
95
101
|
|
data/README.md
CHANGED
@@ -64,10 +64,10 @@ gem "sidekiq-cron"
|
|
64
64
|
'queue' => 'name of queue',
|
65
65
|
'args' => '[Array or Hash] of arguments which will be passed to perform method',
|
66
66
|
'date_as_argument' => true, # add the time of execution as last argument of the perform method
|
67
|
-
'active_job' => true, # enqueue job through
|
68
|
-
'queue_name_prefix' => 'prefix', #
|
69
|
-
'queue_name_delimiter' => '.',
|
70
|
-
'description' => 'A sentence describing what work this job performs
|
67
|
+
'active_job' => true, # enqueue job through Rails 4.2+ Active Job interface
|
68
|
+
'queue_name_prefix' => 'prefix', # Rails 4.2+ Active Job queue with prefix
|
69
|
+
'queue_name_delimiter' => '.', # Rails 4.2+ Active Job queue with custom delimiter
|
70
|
+
'description' => 'A sentence describing what work this job performs'
|
71
71
|
'status' => 'disabled' # default: enabled
|
72
72
|
}
|
73
73
|
```
|
@@ -83,6 +83,17 @@ If using Rails, this is evaluated against the timezone configured in Rails, othe
|
|
83
83
|
If you want to have your jobs enqueued based on a different time zone you can specify a timezone in the cronline,
|
84
84
|
like this `'0 22 * * 1-5 America/Chicago'`.
|
85
85
|
|
86
|
+
#### Natural-language formats
|
87
|
+
|
88
|
+
Since sidekiq-cron `v1.7.0`, you can use the natural-language formats supported by Fugit, such as:
|
89
|
+
|
90
|
+
```rb
|
91
|
+
"every day at five" # => '0 5 * * *'
|
92
|
+
"every 3 hours" # => '0 */3 * * *'
|
93
|
+
```
|
94
|
+
|
95
|
+
See [the relevant part of Fugit documentation](https://github.com/floraison/fugit#fugitnat) for details.
|
96
|
+
|
86
97
|
#### Second-precision (sub-minute) cronlines
|
87
98
|
|
88
99
|
In addition to the standard 5-parameter cronline format, sidekiq-cron supports scheduling jobs with second-precision using a modified 6-parameter cronline format:
|
@@ -248,8 +259,6 @@ Sidekiq.configure_server do |config|
|
|
248
259
|
end
|
249
260
|
```
|
250
261
|
|
251
|
-
Or you can use for loading jobs from yml file [sidekiq-cron-tasks](https://github.com/coverhound/sidekiq-cron-tasks) which will add rake task `bundle exec rake sidekiq_cron:load` to your rails application.
|
252
|
-
|
253
262
|
### Finding jobs
|
254
263
|
|
255
264
|
```ruby
|
@@ -312,8 +321,7 @@ add `require 'sidekiq/cron/web'` after `require 'sidekiq/web'`.
|
|
312
321
|
|
313
322
|
With this, you will get:
|
314
323
|
|
315
|
-
![Web UI](examples/web-cron-ui.
|
316
|
-
|
324
|
+
![Web UI](examples/web-cron-ui.jpeg)
|
317
325
|
|
318
326
|
## Under the hood
|
319
327
|
|
data/lib/sidekiq/cron/job.rb
CHANGED
@@ -1,18 +1,21 @@
|
|
1
1
|
require 'fugit'
|
2
2
|
require 'sidekiq'
|
3
3
|
require 'sidekiq/cron/support'
|
4
|
+
require 'sidekiq/options'
|
4
5
|
|
5
6
|
module Sidekiq
|
6
7
|
module Cron
|
7
8
|
class Job
|
8
|
-
#
|
9
|
+
# How long we would like to store informations about previous enqueues.
|
9
10
|
REMEMBER_THRESHOLD = 24 * 60 * 60
|
11
|
+
|
12
|
+
# Time format for enqueued jobs.
|
10
13
|
LAST_ENQUEUE_TIME_FORMAT = '%Y-%m-%d %H:%M:%S %z'
|
11
14
|
|
12
|
-
# Use the exists? method if we're on a newer version of
|
15
|
+
# Use the exists? method if we're on a newer version of Redis.
|
13
16
|
REDIS_EXISTS_METHOD = Gem.loaded_specs['redis'].version < Gem::Version.new('4.2') ? :exists : :exists?
|
14
17
|
|
15
|
-
#
|
18
|
+
# Crucial part of whole enqueuing job.
|
16
19
|
def should_enque? time
|
17
20
|
enqueue = false
|
18
21
|
enqueue = Sidekiq.redis do |conn|
|
@@ -24,18 +27,16 @@ module Sidekiq
|
|
24
27
|
enqueue
|
25
28
|
end
|
26
29
|
|
27
|
-
#
|
28
|
-
# this will clear
|
29
|
-
# not overflow with memory
|
30
|
+
# Remove previous information about run times,
|
31
|
+
# this will clear Redis and make sure that Redis will not overflow with memory.
|
30
32
|
def remove_previous_enques time
|
31
33
|
Sidekiq.redis do |conn|
|
32
34
|
conn.zremrangebyscore(job_enqueued_key, 0, "(#{(time.to_f - REMEMBER_THRESHOLD).to_s}")
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
|
-
#
|
38
|
+
# Test if job should be enqueued.
|
37
39
|
def test_and_enque_for_time! time
|
38
|
-
#should this job be enqued?
|
39
40
|
if should_enque?(time)
|
40
41
|
enque!
|
41
42
|
|
@@ -43,7 +44,7 @@ module Sidekiq
|
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
46
|
-
#
|
47
|
+
# Enqueue cron job to queue.
|
47
48
|
def enque! time = Time.now.utc
|
48
49
|
@last_enqueue_time = time.strftime(LAST_ENQUEUE_TIME_FORMAT)
|
49
50
|
|
@@ -80,17 +81,27 @@ module Sidekiq
|
|
80
81
|
false
|
81
82
|
end
|
82
83
|
|
84
|
+
def date_as_argument?
|
85
|
+
!!@date_as_argument
|
86
|
+
end
|
87
|
+
|
88
|
+
def enqueue_args
|
89
|
+
date_as_argument? ? @args + [Time.now.to_f] : @args
|
90
|
+
end
|
91
|
+
|
83
92
|
def enqueue_active_job(klass_const)
|
84
|
-
klass_const.set(queue: @queue).perform_later(
|
93
|
+
klass_const.set(queue: @queue).perform_later(*enqueue_args)
|
85
94
|
end
|
86
95
|
|
87
96
|
def enqueue_sidekiq_worker(klass_const)
|
88
|
-
klass_const.set(queue: queue_name_with_prefix).perform_async(
|
97
|
+
klass_const.set(queue: queue_name_with_prefix).perform_async(*enqueue_args)
|
89
98
|
end
|
90
99
|
|
91
|
-
#
|
100
|
+
# Sidekiq worker message.
|
92
101
|
def sidekiq_worker_message
|
93
|
-
@message.is_a?(String) ? Sidekiq.load_json(@message) : @message
|
102
|
+
message = @message.is_a?(String) ? Sidekiq.load_json(@message) : @message
|
103
|
+
message["args"] = enqueue_args
|
104
|
+
message
|
94
105
|
end
|
95
106
|
|
96
107
|
def queue_name_with_prefix
|
@@ -115,8 +126,8 @@ module Sidekiq
|
|
115
126
|
queue_name
|
116
127
|
end
|
117
128
|
|
118
|
-
#
|
119
|
-
# queue, it
|
129
|
+
# Active Job has different structure how it is loading data from Sidekiq
|
130
|
+
# queue, it creates a wrapper around job.
|
120
131
|
def active_job_message
|
121
132
|
{
|
122
133
|
'class' => 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper',
|
@@ -127,13 +138,13 @@ module Sidekiq
|
|
127
138
|
'job_class' => @klass,
|
128
139
|
'job_id' => SecureRandom.uuid,
|
129
140
|
'queue_name' => @queue_name_with_prefix,
|
130
|
-
'arguments' =>
|
141
|
+
'arguments' => enqueue_args
|
131
142
|
}]
|
132
143
|
}
|
133
144
|
end
|
134
145
|
|
135
|
-
#
|
136
|
-
#
|
146
|
+
# Load cron jobs from Hash.
|
147
|
+
# Input structure should look like:
|
137
148
|
# {
|
138
149
|
# 'name_of_job' => {
|
139
150
|
# 'class' => 'MyClass',
|
@@ -155,15 +166,15 @@ module Sidekiq
|
|
155
166
|
load_from_array array
|
156
167
|
end
|
157
168
|
|
158
|
-
#
|
159
|
-
# If exists old jobs in
|
169
|
+
# Like #load_from_hash.
|
170
|
+
# If exists old jobs in Redis but removed from args, destroy old jobs.
|
160
171
|
def self.load_from_hash! hash
|
161
172
|
destroy_removed_jobs(hash.keys)
|
162
173
|
load_from_hash(hash)
|
163
174
|
end
|
164
175
|
|
165
|
-
#
|
166
|
-
#
|
176
|
+
# Load cron jobs from Array.
|
177
|
+
# Input structure should look like:
|
167
178
|
# [
|
168
179
|
# {
|
169
180
|
# 'name' => 'name_of_job',
|
@@ -188,15 +199,15 @@ module Sidekiq
|
|
188
199
|
errors
|
189
200
|
end
|
190
201
|
|
191
|
-
#
|
192
|
-
# If exists old jobs in
|
202
|
+
# Like #load_from_array.
|
203
|
+
# If exists old jobs in Redis but removed from args, destroy old jobs.
|
193
204
|
def self.load_from_array! array
|
194
205
|
job_names = array.map { |job| job["name"] }
|
195
206
|
destroy_removed_jobs(job_names)
|
196
207
|
load_from_array(array)
|
197
208
|
end
|
198
209
|
|
199
|
-
#
|
210
|
+
# Get all cron jobs.
|
200
211
|
def self.all
|
201
212
|
job_hashes = nil
|
202
213
|
Sidekiq.redis do |conn|
|
@@ -208,7 +219,7 @@ module Sidekiq
|
|
208
219
|
end
|
209
220
|
end
|
210
221
|
job_hashes.compact.reject(&:empty?).collect do |h|
|
211
|
-
#
|
222
|
+
# No need to fetch missing args from Redis since we just got this hash from there
|
212
223
|
Sidekiq::Cron::Job.new(h.merge(fetch_missing_args: false))
|
213
224
|
end
|
214
225
|
end
|
@@ -222,7 +233,7 @@ module Sidekiq
|
|
222
233
|
end
|
223
234
|
|
224
235
|
def self.find name
|
225
|
-
#
|
236
|
+
# If name is hash try to get name from it.
|
226
237
|
name = name[:name] || name['name'] if name.is_a?(Hash)
|
227
238
|
|
228
239
|
output = nil
|
@@ -234,14 +245,14 @@ module Sidekiq
|
|
234
245
|
output if output && output.valid?
|
235
246
|
end
|
236
247
|
|
237
|
-
#
|
248
|
+
# Create new instance of cron job.
|
238
249
|
def self.create hash
|
239
250
|
new(hash).save
|
240
251
|
end
|
241
252
|
|
242
|
-
#
|
253
|
+
# Destroy job by name.
|
243
254
|
def self.destroy name
|
244
|
-
#
|
255
|
+
# If name is hash try to get name from it.
|
245
256
|
name = name[:name] || name['name'] if name.is_a?(Hash)
|
246
257
|
|
247
258
|
if job = find(name)
|
@@ -263,23 +274,24 @@ module Sidekiq
|
|
263
274
|
@cron = args["cron"]
|
264
275
|
@description = args["description"] if args["description"]
|
265
276
|
|
266
|
-
#
|
277
|
+
# Get class from klass or class.
|
267
278
|
@klass = args["klass"] || args["class"]
|
268
279
|
|
269
|
-
#
|
280
|
+
# Set status of job.
|
270
281
|
@status = args['status'] || status_from_redis
|
271
282
|
|
272
|
-
#
|
283
|
+
# Set last enqueue time - from args or from existing job.
|
273
284
|
if args['last_enqueue_time'] && !args['last_enqueue_time'].empty?
|
274
285
|
@last_enqueue_time = parse_enqueue_time(args['last_enqueue_time'])
|
275
286
|
else
|
276
287
|
@last_enqueue_time = last_enqueue_time_from_redis
|
277
288
|
end
|
278
289
|
|
279
|
-
#
|
290
|
+
# Get right arguments for job.
|
280
291
|
@symbolize_args = args["symbolize_args"] == true || ("#{args["symbolize_args"]}" =~ (/^(true|t|yes|y|1)$/i)) == 0 || false
|
281
292
|
@args = args["args"].nil? ? [] : parse_args( args["args"] )
|
282
|
-
|
293
|
+
|
294
|
+
@date_as_argument = args["date_as_argument"] == true || ("#{args["date_as_argument"]}" =~ (/^(true|t|yes|y|1)$/i)) == 0 || false
|
283
295
|
|
284
296
|
@active_job = args["active_job"] == true || ("#{args["active_job"]}" =~ (/^(true|t|yes|y|1)$/i)) == 0 || false
|
285
297
|
@active_job_queue_name_prefix = args["queue_name_prefix"]
|
@@ -295,8 +307,8 @@ module Sidekiq
|
|
295
307
|
"args" => @args,
|
296
308
|
}
|
297
309
|
|
298
|
-
#
|
299
|
-
#only if message wasn't specified before
|
310
|
+
# Get right data for message,
|
311
|
+
# only if message wasn't specified before.
|
300
312
|
klass_data = case @klass
|
301
313
|
when Class
|
302
314
|
@klass.get_sidekiq_options
|
@@ -304,21 +316,21 @@ module Sidekiq
|
|
304
316
|
begin
|
305
317
|
Sidekiq::Cron::Support.constantize(@klass).get_sidekiq_options
|
306
318
|
rescue Exception => e
|
307
|
-
#Unknown class
|
319
|
+
# Unknown class
|
308
320
|
{"queue"=>"default"}
|
309
321
|
end
|
310
322
|
end
|
311
323
|
|
312
324
|
message_data = klass_data.merge(message_data)
|
313
|
-
|
314
|
-
#
|
325
|
+
|
326
|
+
# Override queue if setted in config,
|
327
|
+
# only if message is hash - can be string (dumped JSON).
|
315
328
|
if args['queue']
|
316
329
|
@queue = message_data['queue'] = args['queue']
|
317
330
|
else
|
318
331
|
@queue = message_data['queue'] || "default"
|
319
332
|
end
|
320
333
|
|
321
|
-
#dump message as json
|
322
334
|
@message = message_data
|
323
335
|
end
|
324
336
|
|
@@ -380,13 +392,12 @@ module Sidekiq
|
|
380
392
|
conn.lrange(jid_history_key, 0, -1) rescue nil
|
381
393
|
end
|
382
394
|
|
383
|
-
# returns nil if out nil
|
384
395
|
out && out.map do |jid_history_raw|
|
385
396
|
Sidekiq.load_json jid_history_raw
|
386
397
|
end
|
387
398
|
end
|
388
399
|
|
389
|
-
#
|
400
|
+
# Export job data to hash.
|
390
401
|
def to_hash
|
391
402
|
{
|
392
403
|
name: @name,
|
@@ -394,6 +405,7 @@ module Sidekiq
|
|
394
405
|
cron: @cron,
|
395
406
|
description: @description,
|
396
407
|
args: @args.is_a?(String) ? @args : Sidekiq.dump_json(@args || []),
|
408
|
+
date_as_argument: @date_as_argument,
|
397
409
|
message: @message.is_a?(String) ? @message : Sidekiq.dump_json(@message || {}),
|
398
410
|
status: @status,
|
399
411
|
active_job: @active_job,
|
@@ -409,7 +421,7 @@ module Sidekiq
|
|
409
421
|
end
|
410
422
|
|
411
423
|
def valid?
|
412
|
-
#
|
424
|
+
# Clear previous errors.
|
413
425
|
@errors = []
|
414
426
|
|
415
427
|
errors << "'name' must be set" if @name.nil? || @name.size == 0
|
@@ -417,7 +429,15 @@ module Sidekiq
|
|
417
429
|
errors << "'cron' must be set"
|
418
430
|
else
|
419
431
|
begin
|
420
|
-
|
432
|
+
c = Fugit.do_parse(@cron)
|
433
|
+
|
434
|
+
# Since `Fugit.do_parse` might yield a Fugit::Duration or an EtOrbi::EoTime
|
435
|
+
# https://github.com/floraison/fugit#fugitparses
|
436
|
+
if c.is_a?(Fugit::Cron)
|
437
|
+
@parsed_cron = c
|
438
|
+
else
|
439
|
+
errors << "'cron' -> #{@cron.inspect} -> not a cron but a #{c.class}"
|
440
|
+
end
|
421
441
|
rescue => e
|
422
442
|
errors << "'cron' -> #{@cron.inspect} -> #{e.class}: #{e.message}"
|
423
443
|
end
|
@@ -438,28 +458,19 @@ module Sidekiq
|
|
438
458
|
end
|
439
459
|
end
|
440
460
|
|
441
|
-
# add job to cron jobs
|
442
|
-
# input:
|
443
|
-
# name: (string) - name of job
|
444
|
-
# cron: (string: '* * * * *' - cron specification when to run job
|
445
|
-
# class: (string|class) - which class to perform
|
446
|
-
# optional input:
|
447
|
-
# queue: (string) - which queue to use for enquing (will override class queue)
|
448
|
-
# args: (array|hash|nil) - arguments for permorm method
|
449
|
-
|
450
461
|
def save
|
451
|
-
#
|
462
|
+
# If job is invalid, return false.
|
452
463
|
return false unless valid?
|
453
464
|
|
454
465
|
Sidekiq.redis do |conn|
|
455
466
|
|
456
|
-
#
|
467
|
+
# Add to set of all jobs
|
457
468
|
conn.sadd self.class.jobs_key, redis_key
|
458
469
|
|
459
|
-
#
|
470
|
+
# Add informations for this job!
|
460
471
|
conn.hmset redis_key, *hash_to_redis(to_hash)
|
461
472
|
|
462
|
-
#
|
473
|
+
# Add information about last time! - don't enque right after scheduler poller starts!
|
463
474
|
time = Time.now.utc
|
464
475
|
conn.zadd(job_enqueued_key, time.to_f.to_s, formated_last_time(time).to_s) unless conn.public_send(REDIS_EXISTS_METHOD, job_enqueued_key)
|
465
476
|
end
|
@@ -468,7 +479,7 @@ module Sidekiq
|
|
468
479
|
|
469
480
|
def save_last_enqueue_time
|
470
481
|
Sidekiq.redis do |conn|
|
471
|
-
#
|
482
|
+
# Update last enqueue time.
|
472
483
|
conn.hset redis_key, 'last_enqueue_time', @last_enqueue_time
|
473
484
|
end
|
474
485
|
end
|
@@ -478,37 +489,35 @@ module Sidekiq
|
|
478
489
|
jid: jid,
|
479
490
|
enqueued: @last_enqueue_time
|
480
491
|
}
|
481
|
-
|
482
|
-
@history_size ||= (cron_history_size || 10).to_i - 1
|
492
|
+
|
493
|
+
@history_size ||= (Sidekiq::Options[:cron_history_size] || 10).to_i - 1
|
483
494
|
Sidekiq.redis do |conn|
|
484
495
|
conn.lpush jid_history_key,
|
485
496
|
Sidekiq.dump_json(jid_history)
|
486
|
-
#
|
497
|
+
# Keep only last 10 entries in a fifo manner.
|
487
498
|
conn.ltrim jid_history_key, 0, @history_size
|
488
499
|
end
|
489
500
|
end
|
490
501
|
|
491
|
-
# remove job from cron jobs by name
|
492
|
-
# input:
|
493
|
-
# first arg: name (string) - name of job (must be same - case sensitive)
|
494
502
|
def destroy
|
495
503
|
Sidekiq.redis do |conn|
|
496
|
-
#
|
504
|
+
# Delete from set.
|
497
505
|
conn.srem self.class.jobs_key, redis_key
|
498
506
|
|
499
|
-
#
|
507
|
+
# Delete runned timestamps.
|
500
508
|
conn.del job_enqueued_key
|
501
509
|
|
502
|
-
#
|
510
|
+
# Delete jid_history.
|
503
511
|
conn.del jid_history_key
|
504
512
|
|
505
|
-
#
|
513
|
+
# Delete main job.
|
506
514
|
conn.del redis_key
|
507
515
|
end
|
516
|
+
|
508
517
|
Sidekiq.logger.info { "Cron Jobs - deleted job with name: #{@name}" }
|
509
518
|
end
|
510
519
|
|
511
|
-
#
|
520
|
+
# Remove all job from cron.
|
512
521
|
def self.destroy_all!
|
513
522
|
all.each do |job|
|
514
523
|
job.destroy
|
@@ -516,7 +525,7 @@ module Sidekiq
|
|
516
525
|
Sidekiq.logger.info { "Cron Jobs - deleted all jobs" }
|
517
526
|
end
|
518
527
|
|
519
|
-
#
|
528
|
+
# Remove "removed jobs" between current jobs and new jobs
|
520
529
|
def self.destroy_removed_jobs new_job_names
|
521
530
|
current_job_names = Sidekiq::Cron::Job.all.map(&:name)
|
522
531
|
removed_job_names = current_job_names - new_job_names
|
@@ -557,7 +566,19 @@ module Sidekiq
|
|
557
566
|
private
|
558
567
|
|
559
568
|
def parsed_cron
|
560
|
-
@parsed_cron ||=
|
569
|
+
@parsed_cron ||= begin
|
570
|
+
c = Fugit.parse(@cron)
|
571
|
+
|
572
|
+
# Since `Fugit.parse` might yield a Fugit::Duration or an EtOrbi::EoTime
|
573
|
+
# https://github.com/floraison/fugit#fugitparses
|
574
|
+
if c.is_a?(Fugit::Cron)
|
575
|
+
c
|
576
|
+
else
|
577
|
+
errors << "'cron' -> #{@cron.inspect} -> not a cron but a #{c.class}"
|
578
|
+
end
|
579
|
+
rescue => e
|
580
|
+
errors << "'cron' -> #{@cron.inspect} -> #{e.class}: #{e.message}"
|
581
|
+
end
|
561
582
|
end
|
562
583
|
|
563
584
|
def not_enqueued_after?(time)
|
@@ -565,9 +586,8 @@ module Sidekiq
|
|
565
586
|
end
|
566
587
|
|
567
588
|
# Try parsing inbound args into an array.
|
568
|
-
#
|
569
|
-
# try to load JSON, then failover
|
570
|
-
# to string array.
|
589
|
+
# Args from Redis will be encoded JSON,
|
590
|
+
# try to load JSON, then failover to string array.
|
571
591
|
def parse_args(args)
|
572
592
|
case args
|
573
593
|
when String
|
@@ -575,14 +595,14 @@ module Sidekiq
|
|
575
595
|
parsed_args = Sidekiq.load_json(args)
|
576
596
|
symbolize_args? ? symbolize_args(parsed_args) : parsed_args
|
577
597
|
rescue JSON::ParserError
|
578
|
-
[*args]
|
598
|
+
[*args]
|
579
599
|
end
|
580
600
|
when Hash
|
581
601
|
symbolize_args? ? [symbolize_args(args)] : [args]
|
582
602
|
when Array
|
583
603
|
symbolize_args? ? symbolize_args(args) : args
|
584
604
|
else
|
585
|
-
[*args]
|
605
|
+
[*args]
|
586
606
|
end
|
587
607
|
end
|
588
608
|
|
@@ -614,29 +634,26 @@ module Sidekiq
|
|
614
634
|
|
615
635
|
def not_past_scheduled_time?(current_time)
|
616
636
|
last_cron_time = parsed_cron.previous_time(current_time).utc
|
617
|
-
# or could it be?
|
618
|
-
#last_cron_time = last_time(current_time)
|
619
637
|
return false if (current_time.to_i - last_cron_time.to_i) > 60
|
620
638
|
true
|
621
639
|
end
|
622
640
|
|
623
|
-
# Redis key for set of all cron jobs
|
641
|
+
# Redis key for set of all cron jobs.
|
624
642
|
def self.jobs_key
|
625
643
|
"cron_jobs"
|
626
644
|
end
|
627
645
|
|
628
|
-
# Redis key for storing one cron job
|
646
|
+
# Redis key for storing one cron job.
|
629
647
|
def self.redis_key name
|
630
648
|
"cron_job:#{name}"
|
631
649
|
end
|
632
650
|
|
633
|
-
# Redis key for storing one cron job
|
651
|
+
# Redis key for storing one cron job.
|
634
652
|
def redis_key
|
635
653
|
self.class.redis_key @name
|
636
654
|
end
|
637
655
|
|
638
|
-
# Redis key for storing one cron job run times
|
639
|
-
# (when poller added job to queue)
|
656
|
+
# Redis key for storing one cron job run times (when poller added job to queue)
|
640
657
|
def self.job_enqueued_key name
|
641
658
|
"cron_job:#{name}:enqueued"
|
642
659
|
end
|
@@ -645,8 +662,6 @@ module Sidekiq
|
|
645
662
|
"cron_job:#{name}:jid_history"
|
646
663
|
end
|
647
664
|
|
648
|
-
# Redis key for storing one cron job run times
|
649
|
-
# (when poller added job to queue)
|
650
665
|
def job_enqueued_key
|
651
666
|
self.class.job_enqueued_key @name
|
652
667
|
end
|
@@ -655,12 +670,10 @@ module Sidekiq
|
|
655
670
|
self.class.jid_history_key @name
|
656
671
|
end
|
657
672
|
|
658
|
-
# Give Hash
|
659
|
-
# returns array for using it for redis.hmset
|
673
|
+
# Give Hash returns array for using it for redis.hmset
|
660
674
|
def hash_to_redis hash
|
661
675
|
hash.inject([]){ |arr,kv| arr + [kv[0], kv[1]] }
|
662
676
|
end
|
663
|
-
|
664
677
|
end
|
665
678
|
end
|
666
679
|
end
|
@@ -1,36 +1,35 @@
|
|
1
|
-
# require cron poller
|
2
1
|
require 'sidekiq/cron/poller'
|
3
2
|
|
4
3
|
# For Cron we need to add some methods to Launcher
|
5
4
|
# so look at the code bellow.
|
6
5
|
#
|
7
|
-
#
|
8
|
-
# adding start and stop commands to launcher
|
6
|
+
# We are creating new cron poller instance and
|
7
|
+
# adding start and stop commands to launcher.
|
9
8
|
module Sidekiq
|
10
9
|
module Cron
|
11
10
|
module Launcher
|
12
|
-
# Add cron poller to launcher
|
11
|
+
# Add cron poller to launcher.
|
13
12
|
attr_reader :cron_poller
|
14
13
|
|
15
|
-
#
|
14
|
+
# Add cron poller and execute normal initialize of Sidekiq launcher.
|
16
15
|
def initialize(options)
|
17
16
|
@cron_poller = Sidekiq::Cron::Poller.new
|
18
17
|
super(options)
|
19
18
|
end
|
20
19
|
|
21
|
-
#
|
20
|
+
# Execute normal run of launcher and run cron poller.
|
22
21
|
def run
|
23
22
|
super
|
24
23
|
cron_poller.start
|
25
24
|
end
|
26
25
|
|
27
|
-
#
|
26
|
+
# Execute normal quiet of launcher and quiet cron poller.
|
28
27
|
def quiet
|
29
28
|
cron_poller.terminate
|
30
29
|
super
|
31
30
|
end
|
32
31
|
|
33
|
-
#
|
32
|
+
# Execute normal stop of launcher and stop cron poller.
|
34
33
|
def stop
|
35
34
|
cron_poller.terminate
|
36
35
|
super
|
@@ -40,7 +39,6 @@ module Sidekiq
|
|
40
39
|
end
|
41
40
|
|
42
41
|
Sidekiq.configure_server do
|
43
|
-
# require Sidekiq original launcher
|
44
42
|
require 'sidekiq/launcher'
|
45
43
|
|
46
44
|
::Sidekiq::Launcher.prepend(Sidekiq::Cron::Launcher)
|