sidekiq-cron 1.9.0 → 1.12.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/CHANGELOG.md +33 -1
- data/Gemfile +3 -0
- data/README.md +42 -13
- data/lib/sidekiq/cron/job.rb +99 -53
- data/lib/sidekiq/cron/launcher.rb +1 -1
- data/lib/sidekiq/cron/schedule_loader.rb +11 -13
- data/lib/sidekiq/cron/support.rb +8 -0
- data/lib/sidekiq/cron/version.rb +1 -1
- data/lib/sidekiq/options.rb +6 -2
- data/sidekiq-cron.gemspec +7 -5
- metadata +38 -21
- data/test/integration/performance_test.rb +0 -46
- data/test/test_helper.rb +0 -87
- data/test/unit/fixtures/schedule_array.yml +0 -13
- data/test/unit/fixtures/schedule_erb.yml +0 -4
- data/test/unit/fixtures/schedule_hash.yml +0 -12
- data/test/unit/fixtures/schedule_string.yml +0 -1
- data/test/unit/job_test.rb +0 -1228
- data/test/unit/launcher_test.rb +0 -33
- data/test/unit/poller_test.rb +0 -144
- data/test/unit/schedule_loader_test.rb +0 -58
- data/test/unit/web_extension_test.rb +0 -155
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aaa6af217265c4e60b29018b984b43a4316b2618e52ce874db670e41ecadf85b
|
|
4
|
+
data.tar.gz: f70a50a90508ceb32bad90b8b2b6a880fb460f308dfa81f7380152742bb939cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ef95b33d15c1867a3dc6cc096080af6f2fab50c4460d8be24948bcd887c6c278dc3ca1a8c92db8d1ce386d24e0ceb95f53f6add336c3315fec04f808b7451475
|
|
7
|
+
data.tar.gz: e30e02e3bcc13f8604426d5d9e5f30e24c46a85bfd7679544975a3bdfcc0510631d363ef041f948c8a51e289a02a222fd27bba572cf57ac1697aabb917673a01
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 1.12.0
|
|
6
|
+
|
|
7
|
+
- Remove Sidekiq.server? check from schedule loader (https://github.com/sidekiq-cron/sidekiq-cron/pull/436)
|
|
8
|
+
- Parse arguments on `args=` method (https://github.com/sidekiq-cron/sidekiq-cron/pull/442)
|
|
9
|
+
- Only check out a Redis connection if necessary (https://github.com/sidekiq-cron/sidekiq-cron/pull/438)
|
|
10
|
+
|
|
11
|
+
## 1.11.0
|
|
12
|
+
|
|
13
|
+
- Differentiates b/w "schedule" vs "dynamic" jobs (https://github.com/sidekiq-cron/sidekiq-cron/pull/431)
|
|
14
|
+
- Clears scheduled jobs upon schedule load (https://github.com/sidekiq-cron/sidekiq-cron/pull/431)
|
|
15
|
+
- Reduce gem size by excluding test files (https://github.com/sidekiq-cron/sidekiq-cron/pull/414)
|
|
16
|
+
|
|
17
|
+
## 1.10.1
|
|
18
|
+
|
|
19
|
+
- Use `hset` instead of deprecated `hmset` (https://github.com/sidekiq-cron/sidekiq-cron/pull/410)
|
|
20
|
+
|
|
21
|
+
## 1.10.0
|
|
22
|
+
|
|
23
|
+
- Remove EOL Ruby 2.6 support (https://github.com/sidekiq-cron/sidekiq-cron/pull/399)
|
|
24
|
+
- Add a logo for the project! (https://github.com/sidekiq-cron/sidekiq-cron/pull/402)
|
|
25
|
+
- Added support for ActiveRecord serialize/deserialize using GlobalID (https://github.com/sidekiq-cron/sidekiq-cron/pull/395)
|
|
26
|
+
- Allow for keyword args (`embedded: true`) in Poller (https://github.com/sidekiq-cron/sidekiq-cron/pull/398)
|
|
27
|
+
- Make last_enqueue_time be always an instance of Time (https://github.com/sidekiq-cron/sidekiq-cron/pull/354)
|
|
28
|
+
- Fix argument error problem update from 1.6.0 to newer (https://github.com/sidekiq-cron/sidekiq-cron/pull/392)
|
|
29
|
+
- Clear old jobs while loading the jobs from schedule via the schedule loader (https://github.com/sidekiq-cron/sidekiq-cron/pull/405)
|
|
30
|
+
|
|
31
|
+
## 1.9.1
|
|
32
|
+
|
|
33
|
+
- Always enqueue via Active Job interface when defined in cron job config (https://github.com/sidekiq-cron/sidekiq-cron/pull/381)
|
|
34
|
+
- Fix schedule.yml YAML load errors on Ruby 3.1 (https://github.com/sidekiq-cron/sidekiq-cron/pull/386)
|
|
35
|
+
- Require Fugit v1.8 to refactor internals (https://github.com/sidekiq-cron/sidekiq-cron/pull/385)
|
|
36
|
+
|
|
5
37
|
## 1.9.0
|
|
6
38
|
|
|
7
39
|
- Sidekiq v7 support (https://github.com/sidekiq-cron/sidekiq-cron/pull/369)
|
|
@@ -39,7 +71,7 @@ All notable changes to this project will be documented in this file.
|
|
|
39
71
|
## 1.4.0
|
|
40
72
|
|
|
41
73
|
- Fix buttons order in job show view (https://github.com/sidekiq-cron/sidekiq-cron/pull/302)
|
|
42
|
-
- Dark Mode support in UI (https://github.com/sidekiq-cron/sidekiq-cron/pull/
|
|
74
|
+
- Dark Mode support in UI (https://github.com/sidekiq-cron/sidekiq-cron/pull/282)
|
|
43
75
|
- Remove invocation of deprecated Redis functionality (https://github.com/sidekiq-cron/sidekiq-cron/pull/318)
|
|
44
76
|
- Internal code cleanup (https://github.com/sidekiq-cron/sidekiq-cron/pull/317)
|
|
45
77
|
- Optimize gem size (https://github.com/sidekiq-cron/sidekiq-cron/pull/322)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+

|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/sidekiq-cron)
|
|
4
4
|
[](https://github.com/sidekiq-cron/sidekiq-cron/actions)
|
|
5
|
-
[](https://codecov.io/gh/sidekiq-cron/sidekiq-cron)
|
|
6
6
|
|
|
7
7
|
> A scheduling add-on for [Sidekiq](https://sidekiq.org/)
|
|
8
8
|
|
|
@@ -26,12 +26,6 @@ Before upgrading to a new version, please read our [Changelog](CHANGELOG.md).
|
|
|
26
26
|
|
|
27
27
|
## Installation
|
|
28
28
|
|
|
29
|
-
### Requirements
|
|
30
|
-
|
|
31
|
-
- Redis 2.8 or greater is required (Redis 3.0.3 or greater is recommended for large scale use)
|
|
32
|
-
- Sidekiq 4.2 or greater is required (for Sidekiq < 4 use version sidekiq-cron 0.3.1)
|
|
33
|
-
- Sidekiq 6.5 requires Sidekiq-Cron 1.5+
|
|
34
|
-
|
|
35
29
|
Install the gem:
|
|
36
30
|
|
|
37
31
|
```
|
|
@@ -48,7 +42,7 @@ gem "sidekiq-cron"
|
|
|
48
42
|
|
|
49
43
|
## Getting Started
|
|
50
44
|
|
|
51
|
-
|
|
45
|
+
### Job properties
|
|
52
46
|
|
|
53
47
|
```ruby
|
|
54
48
|
{
|
|
@@ -57,12 +51,13 @@ gem "sidekiq-cron"
|
|
|
57
51
|
'cron' => '1 * * * *', # execute at 1 minute of every hour, ex: 12:01, 13:01, 14:01, ...
|
|
58
52
|
'class' => 'MyClass',
|
|
59
53
|
# OPTIONAL
|
|
54
|
+
'source' => 'dynamic', # source of the job, `schedule`/`dynamic` (default: `dynamic`)
|
|
60
55
|
'queue' => 'name of queue',
|
|
61
56
|
'args' => '[Array or Hash] of arguments which will be passed to perform method',
|
|
62
57
|
'date_as_argument' => true, # add the time of execution as last argument of the perform method
|
|
63
58
|
'active_job' => true, # enqueue job through Rails 4.2+ Active Job interface
|
|
64
59
|
'queue_name_prefix' => 'prefix', # Rails 4.2+ Active Job queue with prefix
|
|
65
|
-
'queue_name_delimiter' => '.', # Rails 4.2+ Active Job queue with custom delimiter
|
|
60
|
+
'queue_name_delimiter' => '.', # Rails 4.2+ Active Job queue with custom delimiter (default: '_')
|
|
66
61
|
'description' => 'A sentence describing what work this job performs'
|
|
67
62
|
'status' => 'disabled' # default: enabled
|
|
68
63
|
}
|
|
@@ -141,6 +136,8 @@ which will ensure that arguments you are passing to it will be symbolized when p
|
|
|
141
136
|
|
|
142
137
|
#### Adding Cron job
|
|
143
138
|
|
|
139
|
+
Refer to [Schedule vs Dynamic jobs](#schedule-vs-dynamic-jobs) to understand the difference.
|
|
140
|
+
|
|
144
141
|
```ruby
|
|
145
142
|
class HardWorker
|
|
146
143
|
include Sidekiq::Worker
|
|
@@ -171,6 +168,26 @@ unless job.save
|
|
|
171
168
|
end
|
|
172
169
|
```
|
|
173
170
|
|
|
171
|
+
Use ActiveRecord models as arguments
|
|
172
|
+
|
|
173
|
+
```rb
|
|
174
|
+
class Person < ApplicationRecord
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
class HardWorker < ActiveJob::Base
|
|
178
|
+
queue_as :default
|
|
179
|
+
|
|
180
|
+
def perform(person)
|
|
181
|
+
puts "person: #{person}"
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
person = Person.create(id: 1)
|
|
187
|
+
Sidekiq::Cron::Job.create(name: 'Hard worker - every 5min', cron: '*/5 * * * *', class: 'HardWorker', args: person)
|
|
188
|
+
# => true
|
|
189
|
+
```
|
|
190
|
+
|
|
174
191
|
Load more jobs from hash:
|
|
175
192
|
|
|
176
193
|
```ruby
|
|
@@ -209,7 +226,7 @@ array = [
|
|
|
209
226
|
Sidekiq::Cron::Job.load_from_array array
|
|
210
227
|
```
|
|
211
228
|
|
|
212
|
-
Bang-suffixed methods will remove jobs
|
|
229
|
+
Bang-suffixed methods will remove jobs where source is `schedule` and are not present in the given hash/array, update jobs that have the same names, and create new ones when the names are previously unknown.
|
|
213
230
|
|
|
214
231
|
```ruby
|
|
215
232
|
Sidekiq::Cron::Job.load_from_hash! hash
|
|
@@ -248,7 +265,9 @@ Sidekiq.configure_server do |config|
|
|
|
248
265
|
schedule_file = "config/users_schedule.yml"
|
|
249
266
|
|
|
250
267
|
if File.exist?(schedule_file)
|
|
251
|
-
|
|
268
|
+
schedule = YAML.load_file(schedule_file)
|
|
269
|
+
|
|
270
|
+
Sidekiq::Cron::Job.load_from_hash!(schedule, source: "schedule")
|
|
252
271
|
end
|
|
253
272
|
end
|
|
254
273
|
end
|
|
@@ -301,6 +320,16 @@ job.status
|
|
|
301
320
|
job.enque!
|
|
302
321
|
```
|
|
303
322
|
|
|
323
|
+
### Schedule vs Dynamic jobs
|
|
324
|
+
|
|
325
|
+
There are two potential job sources: `schedule` and `dynamic`.
|
|
326
|
+
Jobs associated with schedule files are labeled as `schedule` as their source,
|
|
327
|
+
whereas jobs created at runtime without the `source=schedule` argument are classified as `dynamic`.
|
|
328
|
+
|
|
329
|
+
The key distinction lies in how these jobs are managed.
|
|
330
|
+
When a schedule is loaded, any stale `schedule` jobs are automatically removed to ensure synchronization within the schedule.
|
|
331
|
+
The `dynamic` jobs remain unaffected by this process.
|
|
332
|
+
|
|
304
333
|
### How to start scheduling?
|
|
305
334
|
|
|
306
335
|
Just start Sidekiq workers by running:
|
|
@@ -316,7 +345,7 @@ add `require 'sidekiq/cron/web'` after `require 'sidekiq/web'`.
|
|
|
316
345
|
|
|
317
346
|
With this, you will get:
|
|
318
347
|
|
|
319
|
-

|
|
320
349
|
|
|
321
350
|
## Under the hood
|
|
322
351
|
|
data/lib/sidekiq/cron/job.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'fugit'
|
|
2
|
+
require 'globalid'
|
|
2
3
|
require 'sidekiq'
|
|
3
4
|
require 'sidekiq/cron/support'
|
|
4
5
|
require 'sidekiq/options'
|
|
@@ -15,13 +16,17 @@ module Sidekiq
|
|
|
15
16
|
# Use the exists? method if we're on a newer version of Redis.
|
|
16
17
|
REDIS_EXISTS_METHOD = Gem::Version.new(Sidekiq::VERSION) >= Gem::Version.new("7.0.0") || Gem.loaded_specs['redis'].version < Gem::Version.new('4.2') ? :exists : :exists?
|
|
17
18
|
|
|
19
|
+
# Use serialize/deserialize key of GlobalID.
|
|
20
|
+
GLOBALID_KEY = "_sc_globalid"
|
|
21
|
+
|
|
18
22
|
# Crucial part of whole enqueuing job.
|
|
19
23
|
def should_enque? time
|
|
24
|
+
return false unless status == "enabled"
|
|
25
|
+
return false unless not_past_scheduled_time?(time)
|
|
26
|
+
return false unless not_enqueued_after?(time)
|
|
27
|
+
|
|
20
28
|
enqueue = Sidekiq.redis do |conn|
|
|
21
|
-
|
|
22
|
-
not_past_scheduled_time?(time) &&
|
|
23
|
-
not_enqueued_after?(time) &&
|
|
24
|
-
conn.zadd(job_enqueued_key, formatted_enqueue_time(time), formatted_last_time(time))
|
|
29
|
+
conn.zadd(job_enqueued_key, formatted_enqueue_time(time), formatted_last_time(time))
|
|
25
30
|
end
|
|
26
31
|
enqueue == true || enqueue == 1
|
|
27
32
|
end
|
|
@@ -45,7 +50,7 @@ module Sidekiq
|
|
|
45
50
|
|
|
46
51
|
# Enqueue cron job to queue.
|
|
47
52
|
def enque! time = Time.now.utc
|
|
48
|
-
@last_enqueue_time = time
|
|
53
|
+
@last_enqueue_time = time
|
|
49
54
|
|
|
50
55
|
klass_const =
|
|
51
56
|
begin
|
|
@@ -56,7 +61,7 @@ module Sidekiq
|
|
|
56
61
|
|
|
57
62
|
jid =
|
|
58
63
|
if klass_const
|
|
59
|
-
if
|
|
64
|
+
if is_active_job?(klass_const)
|
|
60
65
|
enqueue_active_job(klass_const).try :provider_job_id
|
|
61
66
|
else
|
|
62
67
|
enqueue_sidekiq_worker(klass_const)
|
|
@@ -74,8 +79,8 @@ module Sidekiq
|
|
|
74
79
|
Sidekiq.logger.debug { "enqueued #{@name}: #{@message}" }
|
|
75
80
|
end
|
|
76
81
|
|
|
77
|
-
def is_active_job?
|
|
78
|
-
@active_job || defined?(ActiveJob::Base) && Sidekiq::Cron::Support.constantize(@klass.to_s) < ActiveJob::Base
|
|
82
|
+
def is_active_job?(klass = nil)
|
|
83
|
+
@active_job || defined?(ActiveJob::Base) && (klass || Sidekiq::Cron::Support.constantize(@klass.to_s)) < ActiveJob::Base
|
|
79
84
|
rescue NameError
|
|
80
85
|
false
|
|
81
86
|
end
|
|
@@ -85,7 +90,8 @@ module Sidekiq
|
|
|
85
90
|
end
|
|
86
91
|
|
|
87
92
|
def enqueue_args
|
|
88
|
-
date_as_argument? ? @args + [Time.now.to_f] : @args
|
|
93
|
+
args = date_as_argument? ? @args + [Time.now.to_f] : @args
|
|
94
|
+
deserialize_argument(args)
|
|
89
95
|
end
|
|
90
96
|
|
|
91
97
|
def enqueue_active_job(klass_const)
|
|
@@ -157,19 +163,19 @@ module Sidekiq
|
|
|
157
163
|
# }
|
|
158
164
|
# }
|
|
159
165
|
#
|
|
160
|
-
def self.load_from_hash
|
|
166
|
+
def self.load_from_hash(hash, options = {})
|
|
161
167
|
array = hash.map do |key, job|
|
|
162
168
|
job['name'] = key
|
|
163
169
|
job
|
|
164
170
|
end
|
|
165
|
-
load_from_array
|
|
171
|
+
load_from_array(array, options)
|
|
166
172
|
end
|
|
167
173
|
|
|
168
174
|
# Like #load_from_hash.
|
|
169
175
|
# If exists old jobs in Redis but removed from args, destroy old jobs.
|
|
170
|
-
def self.load_from_hash!
|
|
176
|
+
def self.load_from_hash!(hash, options = {})
|
|
171
177
|
destroy_removed_jobs(hash.keys)
|
|
172
|
-
load_from_hash(hash)
|
|
178
|
+
load_from_hash(hash, options)
|
|
173
179
|
end
|
|
174
180
|
|
|
175
181
|
# Load cron jobs from Array.
|
|
@@ -189,10 +195,10 @@ module Sidekiq
|
|
|
189
195
|
# }
|
|
190
196
|
# ]
|
|
191
197
|
#
|
|
192
|
-
def self.load_from_array
|
|
198
|
+
def self.load_from_array(array, options = {})
|
|
193
199
|
errors = {}
|
|
194
200
|
array.each do |job_data|
|
|
195
|
-
job = new(job_data)
|
|
201
|
+
job = new(job_data.merge(options))
|
|
196
202
|
errors[job.name] = job.errors unless job.save
|
|
197
203
|
end
|
|
198
204
|
errors
|
|
@@ -200,10 +206,10 @@ module Sidekiq
|
|
|
200
206
|
|
|
201
207
|
# Like #load_from_array.
|
|
202
208
|
# If exists old jobs in Redis but removed from args, destroy old jobs.
|
|
203
|
-
def self.load_from_array!
|
|
209
|
+
def self.load_from_array!(array, options = {})
|
|
204
210
|
job_names = array.map { |job| job["name"] }
|
|
205
211
|
destroy_removed_jobs(job_names)
|
|
206
|
-
load_from_array(array)
|
|
212
|
+
load_from_array(array, options)
|
|
207
213
|
end
|
|
208
214
|
|
|
209
215
|
# Get all cron jobs.
|
|
@@ -234,12 +240,11 @@ module Sidekiq
|
|
|
234
240
|
def self.find name
|
|
235
241
|
# If name is hash try to get name from it.
|
|
236
242
|
name = name[:name] || name['name'] if name.is_a?(Hash)
|
|
243
|
+
return unless exists? name
|
|
237
244
|
|
|
238
245
|
output = nil
|
|
239
246
|
Sidekiq.redis do |conn|
|
|
240
|
-
|
|
241
|
-
output = Job.new conn.hgetall( redis_key(name) )
|
|
242
|
-
end
|
|
247
|
+
output = Job.new conn.hgetall( redis_key(name) )
|
|
243
248
|
end
|
|
244
249
|
output if output && output.valid?
|
|
245
250
|
end
|
|
@@ -262,7 +267,7 @@ module Sidekiq
|
|
|
262
267
|
end
|
|
263
268
|
|
|
264
269
|
attr_accessor :name, :cron, :description, :klass, :args, :message
|
|
265
|
-
attr_reader :last_enqueue_time, :fetch_missing_args
|
|
270
|
+
attr_reader :last_enqueue_time, :fetch_missing_args, :source
|
|
266
271
|
|
|
267
272
|
def initialize input_args = {}
|
|
268
273
|
args = Hash[input_args.map{ |k, v| [k.to_s, v] }]
|
|
@@ -272,6 +277,7 @@ module Sidekiq
|
|
|
272
277
|
@name = args["name"]
|
|
273
278
|
@cron = args["cron"]
|
|
274
279
|
@description = args["description"] if args["description"]
|
|
280
|
+
@source = args["source"] == "schedule" ? "schedule" : "dynamic"
|
|
275
281
|
|
|
276
282
|
# Get class from klass or class.
|
|
277
283
|
@klass = args["klass"] || args["class"]
|
|
@@ -288,7 +294,7 @@ module Sidekiq
|
|
|
288
294
|
|
|
289
295
|
# Get right arguments for job.
|
|
290
296
|
@symbolize_args = args["symbolize_args"] == true || ("#{args["symbolize_args"]}" =~ (/^(true|t|yes|y|1)$/i)) == 0 || false
|
|
291
|
-
@args =
|
|
297
|
+
@args = parse_args(args["args"])
|
|
292
298
|
|
|
293
299
|
@date_as_argument = args["date_as_argument"] == true || ("#{args["date_as_argument"]}" =~ (/^(true|t|yes|y|1)$/i)) == 0 || false
|
|
294
300
|
|
|
@@ -398,21 +404,27 @@ module Sidekiq
|
|
|
398
404
|
|
|
399
405
|
# Export job data to hash.
|
|
400
406
|
def to_hash
|
|
401
|
-
{
|
|
407
|
+
hash = {
|
|
402
408
|
name: @name,
|
|
403
409
|
klass: @klass.to_s,
|
|
404
410
|
cron: @cron,
|
|
405
411
|
description: @description,
|
|
412
|
+
source: @source,
|
|
406
413
|
args: @args.is_a?(String) ? @args : Sidekiq.dump_json(@args || []),
|
|
407
|
-
date_as_argument: date_as_argument? ? "1" : "0",
|
|
408
414
|
message: @message.is_a?(String) ? @message : Sidekiq.dump_json(@message || {}),
|
|
409
415
|
status: @status,
|
|
410
416
|
active_job: @active_job ? "1" : "0",
|
|
411
417
|
queue_name_prefix: @active_job_queue_name_prefix,
|
|
412
418
|
queue_name_delimiter: @active_job_queue_name_delimiter,
|
|
413
|
-
last_enqueue_time:
|
|
419
|
+
last_enqueue_time: serialized_last_enqueue_time,
|
|
414
420
|
symbolize_args: symbolize_args? ? "1" : "0",
|
|
415
421
|
}
|
|
422
|
+
|
|
423
|
+
if date_as_argument?
|
|
424
|
+
hash.merge!(date_as_argument: "1")
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
hash
|
|
416
428
|
end
|
|
417
429
|
|
|
418
430
|
def errors
|
|
@@ -428,15 +440,7 @@ module Sidekiq
|
|
|
428
440
|
errors << "'cron' must be set"
|
|
429
441
|
else
|
|
430
442
|
begin
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
# Since `Fugit.do_parse` might yield a Fugit::Duration or an EtOrbi::EoTime
|
|
434
|
-
# https://github.com/floraison/fugit#fugitparses
|
|
435
|
-
if c.is_a?(Fugit::Cron)
|
|
436
|
-
@parsed_cron = c
|
|
437
|
-
else
|
|
438
|
-
errors << "'cron' -> #{@cron.inspect} -> not a cron but a #{c.class}"
|
|
439
|
-
end
|
|
443
|
+
@parsed_cron = Fugit.do_parse_cronish(@cron)
|
|
440
444
|
rescue => e
|
|
441
445
|
errors << "'cron' -> #{@cron.inspect} -> #{e.class}: #{e.message}"
|
|
442
446
|
end
|
|
@@ -467,7 +471,7 @@ module Sidekiq
|
|
|
467
471
|
conn.sadd self.class.jobs_key, [redis_key]
|
|
468
472
|
|
|
469
473
|
# Add informations for this job!
|
|
470
|
-
conn.
|
|
474
|
+
conn.hset redis_key, to_hash.transform_values! { |v| v || "" }
|
|
471
475
|
|
|
472
476
|
# Add information about last time! - don't enque right after scheduler poller starts!
|
|
473
477
|
time = Time.now.utc
|
|
@@ -480,7 +484,7 @@ module Sidekiq
|
|
|
480
484
|
def save_last_enqueue_time
|
|
481
485
|
Sidekiq.redis do |conn|
|
|
482
486
|
# Update last enqueue time.
|
|
483
|
-
conn.hset redis_key, 'last_enqueue_time',
|
|
487
|
+
conn.hset redis_key, 'last_enqueue_time', serialized_last_enqueue_time
|
|
484
488
|
end
|
|
485
489
|
end
|
|
486
490
|
|
|
@@ -527,7 +531,7 @@ module Sidekiq
|
|
|
527
531
|
|
|
528
532
|
# Remove "removed jobs" between current jobs and new jobs
|
|
529
533
|
def self.destroy_removed_jobs new_job_names
|
|
530
|
-
current_job_names = Sidekiq::Cron::Job.all.
|
|
534
|
+
current_job_names = Sidekiq::Cron::Job.all.filter_map { |j| j.name if j.source == "schedule" }
|
|
531
535
|
removed_job_names = current_job_names - new_job_names
|
|
532
536
|
removed_job_names.each { |j| Sidekiq::Cron::Job.destroy(j) }
|
|
533
537
|
removed_job_names
|
|
@@ -562,22 +566,14 @@ module Sidekiq
|
|
|
562
566
|
"#{status == "enabled" ? 0 : 1}_#{name}".downcase
|
|
563
567
|
end
|
|
564
568
|
|
|
569
|
+
def args=(args)
|
|
570
|
+
@args = parse_args(args)
|
|
571
|
+
end
|
|
572
|
+
|
|
565
573
|
private
|
|
566
574
|
|
|
567
575
|
def parsed_cron
|
|
568
|
-
@parsed_cron ||=
|
|
569
|
-
c = Fugit.parse(@cron)
|
|
570
|
-
|
|
571
|
-
# Since `Fugit.parse` might yield a Fugit::Duration or an EtOrbi::EoTime
|
|
572
|
-
# https://github.com/floraison/fugit#fugitparses
|
|
573
|
-
if c.is_a?(Fugit::Cron)
|
|
574
|
-
c
|
|
575
|
-
else
|
|
576
|
-
errors << "'cron' -> #{@cron.inspect} -> not a cron but a #{c.class}"
|
|
577
|
-
end
|
|
578
|
-
rescue => e
|
|
579
|
-
errors << "'cron' -> #{@cron.inspect} -> #{e.class}: #{e.message}"
|
|
580
|
-
end
|
|
576
|
+
@parsed_cron ||= Fugit.parse_cronish(@cron)
|
|
581
577
|
end
|
|
582
578
|
|
|
583
579
|
def not_enqueued_after?(time)
|
|
@@ -589,6 +585,8 @@ module Sidekiq
|
|
|
589
585
|
# try to load JSON, then failover to string array.
|
|
590
586
|
def parse_args(args)
|
|
591
587
|
case args
|
|
588
|
+
when GlobalID::Identification
|
|
589
|
+
[convert_to_global_id_hash(args)]
|
|
592
590
|
when String
|
|
593
591
|
begin
|
|
594
592
|
parsed_args = Sidekiq.load_json(args)
|
|
@@ -597,8 +595,10 @@ module Sidekiq
|
|
|
597
595
|
[*args]
|
|
598
596
|
end
|
|
599
597
|
when Hash
|
|
598
|
+
args = serialize_argument(args)
|
|
600
599
|
symbolize_args? ? [symbolize_args(args)] : [args]
|
|
601
600
|
when Array
|
|
601
|
+
args = serialize_argument(args)
|
|
602
602
|
symbolize_args? ? symbolize_args(args) : args
|
|
603
603
|
else
|
|
604
604
|
[*args]
|
|
@@ -669,9 +669,55 @@ module Sidekiq
|
|
|
669
669
|
self.class.jid_history_key @name
|
|
670
670
|
end
|
|
671
671
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
672
|
+
def serialized_last_enqueue_time
|
|
673
|
+
@last_enqueue_time&.strftime(LAST_ENQUEUE_TIME_FORMAT)
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
def convert_to_global_id_hash(argument)
|
|
677
|
+
{ GLOBALID_KEY => argument.to_global_id.to_s }
|
|
678
|
+
rescue URI::GID::MissingModelIdError
|
|
679
|
+
raise "Unable to serialize #{argument.class} " \
|
|
680
|
+
"without an id. (Maybe you forgot to call save?)"
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
def deserialize_argument(argument)
|
|
684
|
+
case argument
|
|
685
|
+
when String
|
|
686
|
+
argument
|
|
687
|
+
when Array
|
|
688
|
+
argument.map { |arg| deserialize_argument(arg) }
|
|
689
|
+
when Hash
|
|
690
|
+
if serialized_global_id?(argument)
|
|
691
|
+
deserialize_global_id argument
|
|
692
|
+
else
|
|
693
|
+
argument.transform_values { |v| deserialize_argument(v) }
|
|
694
|
+
end
|
|
695
|
+
else
|
|
696
|
+
argument
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
def serialized_global_id?(hash)
|
|
701
|
+
hash.size == 1 && hash.include?(GLOBALID_KEY)
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
def deserialize_global_id(hash)
|
|
705
|
+
GlobalID::Locator.locate hash[GLOBALID_KEY]
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
def serialize_argument(argument)
|
|
709
|
+
case argument
|
|
710
|
+
when GlobalID::Identification
|
|
711
|
+
convert_to_global_id_hash(argument)
|
|
712
|
+
when Array
|
|
713
|
+
argument.map { |arg| serialize_argument(arg) }
|
|
714
|
+
when Hash
|
|
715
|
+
argument.each_with_object({}) do |(key, value), hash|
|
|
716
|
+
hash[key] = serialize_argument(value)
|
|
717
|
+
end
|
|
718
|
+
else
|
|
719
|
+
argument
|
|
720
|
+
end
|
|
675
721
|
end
|
|
676
722
|
end
|
|
677
723
|
end
|
|
@@ -14,7 +14,7 @@ module Sidekiq
|
|
|
14
14
|
attr_reader :cron_poller
|
|
15
15
|
|
|
16
16
|
# Add cron poller and execute normal initialize of Sidekiq launcher.
|
|
17
|
-
def initialize(config)
|
|
17
|
+
def initialize(config, **kwargs)
|
|
18
18
|
config[:cron_poll_interval] = DEFAULT_POLL_INTERVAL if config[:cron_poll_interval].nil?
|
|
19
19
|
|
|
20
20
|
@cron_poller = Sidekiq::Cron::Poller.new(config) if config[:cron_poll_interval] > 0
|
|
@@ -2,20 +2,18 @@ require 'sidekiq'
|
|
|
2
2
|
require 'sidekiq/cron/job'
|
|
3
3
|
require 'sidekiq/options'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
Sidekiq
|
|
7
|
-
schedule_file = Sidekiq::Options[:cron_schedule_file] || 'config/schedule.yml'
|
|
5
|
+
Sidekiq.configure_server do |config|
|
|
6
|
+
schedule_file = Sidekiq::Options[:cron_schedule_file] || 'config/schedule.yml'
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
end
|
|
8
|
+
if File.exist?(schedule_file)
|
|
9
|
+
config.on(:startup) do
|
|
10
|
+
schedule = Sidekiq::Cron::Support.load_yaml(ERB.new(IO.read(schedule_file)).result)
|
|
11
|
+
if schedule.kind_of?(Hash)
|
|
12
|
+
Sidekiq::Cron::Job.load_from_hash!(schedule, source: "schedule")
|
|
13
|
+
elsif schedule.kind_of?(Array)
|
|
14
|
+
Sidekiq::Cron::Job.load_from_array!(schedule, source: "schedule")
|
|
15
|
+
else
|
|
16
|
+
raise "Not supported schedule format. Confirm your #{schedule_file}"
|
|
19
17
|
end
|
|
20
18
|
end
|
|
21
19
|
end
|
data/lib/sidekiq/cron/support.rb
CHANGED
data/lib/sidekiq/cron/version.rb
CHANGED
data/lib/sidekiq/options.rb
CHANGED
|
@@ -3,11 +3,15 @@ require 'sidekiq'
|
|
|
3
3
|
module Sidekiq
|
|
4
4
|
module Options
|
|
5
5
|
def self.[](key)
|
|
6
|
-
|
|
6
|
+
self.config[key]
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def self.[]=(key, value)
|
|
10
|
-
|
|
10
|
+
self.config[key] = value
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.config
|
|
14
|
+
options_field ? Sidekiq.public_send(options_field) : Sidekiq
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
def self.options_field
|
data/sidekiq-cron.gemspec
CHANGED
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
|
15
15
|
"LICENSE.txt",
|
|
16
16
|
"README.md"
|
|
17
17
|
]
|
|
18
|
-
s.files = Dir.glob('lib/**/*') +
|
|
18
|
+
s.files = Dir.glob('lib/**/*') + [
|
|
19
19
|
"CHANGELOG.md",
|
|
20
20
|
"Gemfile",
|
|
21
21
|
"LICENSE.txt",
|
|
@@ -24,15 +24,17 @@ Gem::Specification.new do |s|
|
|
|
24
24
|
"sidekiq-cron.gemspec",
|
|
25
25
|
]
|
|
26
26
|
|
|
27
|
-
s.required_ruby_version = ">= 2.
|
|
27
|
+
s.required_ruby_version = ">= 2.7"
|
|
28
28
|
|
|
29
|
-
s.add_dependency("fugit", "~> 1")
|
|
30
|
-
s.add_dependency("sidekiq", ">=
|
|
29
|
+
s.add_dependency("fugit", "~> 1.8")
|
|
30
|
+
s.add_dependency("sidekiq", ">= 6")
|
|
31
|
+
s.add_dependency("globalid", ">= 1.0.1")
|
|
31
32
|
|
|
32
33
|
s.add_development_dependency("minitest", "~> 5.15")
|
|
33
|
-
s.add_development_dependency("mocha", "~> 1
|
|
34
|
+
s.add_development_dependency("mocha", "~> 2.1")
|
|
34
35
|
s.add_development_dependency("rack", "~> 2.2")
|
|
35
36
|
s.add_development_dependency("rack-test", "~> 1.1")
|
|
36
37
|
s.add_development_dependency("rake", "~> 13.0")
|
|
37
38
|
s.add_development_dependency("simplecov", "~> 0.21")
|
|
39
|
+
s.add_development_dependency("simplecov-cobertura", "~> 2.1")
|
|
38
40
|
end
|