sidekiq_schedulable 0.0.1
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 +7 -0
- data/.gitignore +2 -0
- data/Gemfile +3 -0
- data/README.md +23 -0
- data/lib/sidekiq/schedulable.rb +16 -0
- data/lib/sidekiq_schedulable.rb +35 -0
- data/lib/sidekiq_schedulable/middleware/client.rb +16 -0
- data/lib/sidekiq_schedulable/middleware/server.rb +21 -0
- data/lib/sidekiq_schedulable/schedule.rb +9 -0
- data/lib/sidekiq_schedulable/startup.rb +40 -0
- data/lib/sidekiq_schedulable/version.rb +3 -0
- data/sidekiq_schedulable.gemspec +22 -0
- data/spec/sidekiq_schedulable_spec.rb +110 -0
- data/spec/spec_helper.rb +5 -0
- metadata +112 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 558a8b58ecf33d2edc81636f2f5ba511100a6378
|
4
|
+
data.tar.gz: 8a4596c211c0f8c14a4dfbe2afe14f1a26c312c9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8b0da8f414f5fc013f18dd7f4d1c321662f883c3e5e94ccd780f7b280430b86ae76c9f34793508b3e951a7bc3dc2b943e4abeeabe141a7066edda7c31f72c18d
|
7
|
+
data.tar.gz: 2a7ffab36ba92166caffe4e197b86784e4d327a2b484e3d30ee00325ff4bb24e873f7ce868490e36911e1b9d36378bd88995e154bb7a62823ee657a425657b5e
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Sidekiq Schedulable
|
2
|
+
|
3
|
+
Schedule Cron style Sidekiq jobs
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require 'sidekiq_schedulable'
|
9
|
+
```
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class MyJob
|
13
|
+
include Sidekiq::Worker
|
14
|
+
include Sidekiq::Schedulable
|
15
|
+
|
16
|
+
sidekiq_options retry: false, queue: 'my_scheduled_jobs_queue'
|
17
|
+
sidekiq_schedule '*/5 * * * * *'
|
18
|
+
|
19
|
+
def perform
|
20
|
+
RunReport.call
|
21
|
+
end
|
22
|
+
end
|
23
|
+
```
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Schedulable
|
3
|
+
def self.included(klass)
|
4
|
+
klass.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def sidekiq_schedule(schedule)
|
9
|
+
SidekiqSchedulable.schedules[self.to_s] = {
|
10
|
+
worker: self,
|
11
|
+
at: schedule
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
require 'sidekiq/schedulable'
|
3
|
+
require 'sidekiq_schedulable/startup'
|
4
|
+
require 'sidekiq_schedulable/middleware/server'
|
5
|
+
require 'sidekiq_schedulable/middleware/client'
|
6
|
+
|
7
|
+
module SidekiqSchedulable
|
8
|
+
def self.schedules
|
9
|
+
@schedules ||= {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.boot!
|
13
|
+
Sidekiq.configure_server do |config|
|
14
|
+
config.server_middleware do |chain|
|
15
|
+
chain.add Middleware::Server
|
16
|
+
end
|
17
|
+
|
18
|
+
config.client_middleware do |chain|
|
19
|
+
chain.add Middleware::Client, schedules
|
20
|
+
end
|
21
|
+
|
22
|
+
config.on(:startup) do
|
23
|
+
Startup.new(schedules, Sidekiq::ScheduledSet.new).schedule!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Sidekiq.configure_client do |config|
|
28
|
+
config.client_middleware do |chain|
|
29
|
+
chain.add Middleware::Client, schedules
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
SidekiqSchedulable.boot!
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SidekiqSchedulable
|
2
|
+
module Middleware
|
3
|
+
class Client
|
4
|
+
def initialize(schedules = {})
|
5
|
+
@schedules = schedules
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(worker_class, item, queue, redis_pool)
|
9
|
+
if schedule = @schedules[worker_class]
|
10
|
+
item['schedule'] = schedule[:at]
|
11
|
+
end
|
12
|
+
yield
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'sidekiq_schedulable/schedule'
|
2
|
+
|
3
|
+
module SidekiqSchedulable
|
4
|
+
module Middleware
|
5
|
+
class Server
|
6
|
+
def call(worker, item, queue)
|
7
|
+
yield
|
8
|
+
ensure
|
9
|
+
schedule_next_job(worker, item) if item['schedule']
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def schedule_next_job(worker, item)
|
15
|
+
schedule = item['schedule']
|
16
|
+
time = Schedule.next_time(schedule)
|
17
|
+
worker.class.perform_at(time)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'sidekiq_schedulable/schedule'
|
2
|
+
|
3
|
+
module SidekiqSchedulable
|
4
|
+
class Startup
|
5
|
+
def self.schedule!(schedules, current_jobs)
|
6
|
+
new(schedules, current_jobs).schedule!
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(schedules, current_jobs)
|
10
|
+
@schedules = schedules
|
11
|
+
@current_jobs = current_jobs
|
12
|
+
end
|
13
|
+
|
14
|
+
def schedule!
|
15
|
+
schedules.each do |worker_class, schedule|
|
16
|
+
unless already_scheduled?(worker_class)
|
17
|
+
time = Schedule.next_time(schedule[:at])
|
18
|
+
worker = schedule[:worker]
|
19
|
+
worker.perform_at(time)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :schedules, :current_jobs
|
27
|
+
|
28
|
+
def already_scheduled?(worker_class)
|
29
|
+
scheduled_jobs.any? do |job|
|
30
|
+
job.item['class'] == worker_class
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def scheduled_jobs
|
35
|
+
@scheduled_jobs ||= current_jobs.select do |job|
|
36
|
+
job.item['schedule']
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'sidekiq_schedulable/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "sidekiq_schedulable"
|
7
|
+
spec.version = SidekiqSchedulable::VERSION
|
8
|
+
spec.authors = ["Kevin Buchanan"]
|
9
|
+
spec.summary = "Scheduled Sidekiq jobs"
|
10
|
+
spec.description = "Schedule Cron style Sidekiq jobs"
|
11
|
+
spec.homepage = "https://github.com/kevinbuch/sidekiq_schedulable"
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
15
|
+
spec.require_paths = ["lib"]
|
16
|
+
|
17
|
+
spec.add_dependency "sidekiq", "~> 3.0"
|
18
|
+
spec.add_dependency "parse-cron", "~> 0.1.4"
|
19
|
+
|
20
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
21
|
+
spec.add_development_dependency "timecop", "~> 0.8.0"
|
22
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'sidekiq_schedulable'
|
2
|
+
require 'sidekiq'
|
3
|
+
require 'sidekiq/testing'
|
4
|
+
require 'timecop'
|
5
|
+
|
6
|
+
describe SidekiqSchedulable do
|
7
|
+
|
8
|
+
Sidekiq::Testing.fake!
|
9
|
+
|
10
|
+
class TestWorker
|
11
|
+
include Sidekiq::Worker
|
12
|
+
include Sidekiq::Schedulable
|
13
|
+
|
14
|
+
sidekiq_schedule '*/10 * * * * *'
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:midnight) { Time.new(2015, 10, 1, 0, 0, 0) }
|
18
|
+
let(:next_ten_minutes) { midnight + 10 * 60 }
|
19
|
+
|
20
|
+
before do
|
21
|
+
Timecop.freeze(midnight)
|
22
|
+
end
|
23
|
+
|
24
|
+
after do
|
25
|
+
TestWorker.jobs.clear
|
26
|
+
end
|
27
|
+
|
28
|
+
it "adds the schedule to the schedules" do
|
29
|
+
schedule = SidekiqSchedulable.schedules["TestWorker"]
|
30
|
+
|
31
|
+
expect(schedule[:at]).to eq('*/10 * * * * *')
|
32
|
+
expect(schedule[:worker]).to eq(TestWorker)
|
33
|
+
end
|
34
|
+
|
35
|
+
describe SidekiqSchedulable::Middleware::Server do
|
36
|
+
let(:worker) { TestWorker.new }
|
37
|
+
let(:middleware) { SidekiqSchedulable::Middleware::Server.new }
|
38
|
+
|
39
|
+
it "ensures the job is re-enqueued for next time" do
|
40
|
+
expect {
|
41
|
+
middleware.call(worker, { 'schedule' => '*/10 * * * * *' }, 'a queue') do
|
42
|
+
raise "Error"
|
43
|
+
end
|
44
|
+
}.to raise_error RuntimeError, "Error"
|
45
|
+
|
46
|
+
jobs = TestWorker.jobs
|
47
|
+
|
48
|
+
expect(jobs.size).to eq(1)
|
49
|
+
expect(jobs.first['at']).to eq(next_ten_minutes.to_f)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "does not re-schedule if the job has no schedule" do
|
53
|
+
middleware.call(worker, {}, 'a queue') do
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
expect(TestWorker.jobs.size).to eq(0)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
let(:schedules) {
|
62
|
+
{ "TestWorker" => { worker: TestWorker, at: '*/10 * * * * *' } }
|
63
|
+
}
|
64
|
+
|
65
|
+
describe SidekiqSchedulable::Middleware::Client do
|
66
|
+
let(:middleware) { SidekiqSchedulable::Middleware::Client.new(schedules) }
|
67
|
+
|
68
|
+
it "adds the schedule to the job item" do
|
69
|
+
item = {}
|
70
|
+
|
71
|
+
middleware.call("TestWorker", item, "a queue", nil) do
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
expect(item['schedule']).to eq('*/10 * * * * *')
|
76
|
+
end
|
77
|
+
|
78
|
+
it "does not add the schedule if the worker has no schedule" do
|
79
|
+
item = {}
|
80
|
+
|
81
|
+
middleware.call("Array", item, "a queue", nil) do
|
82
|
+
true
|
83
|
+
end
|
84
|
+
|
85
|
+
expect(item['schedule']).to be_nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe SidekiqSchedulable::Startup do
|
90
|
+
Job = Struct.new(:item)
|
91
|
+
|
92
|
+
def current_jobs
|
93
|
+
TestWorker.jobs.map { |item| Job.new(item) }
|
94
|
+
end
|
95
|
+
|
96
|
+
it "enqueues a job for the given worker on an empty queue" do
|
97
|
+
SidekiqSchedulable::Startup.schedule!(schedules, current_jobs)
|
98
|
+
|
99
|
+
expect(TestWorker.jobs.size).to eq(1)
|
100
|
+
expect(TestWorker.jobs.first['at']).to eq(next_ten_minutes.to_f)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "does not enqueue a duplicate job for the given worker" do
|
104
|
+
SidekiqSchedulable::Startup.schedule!(schedules, current_jobs)
|
105
|
+
SidekiqSchedulable::Startup.schedule!(schedules, current_jobs)
|
106
|
+
|
107
|
+
expect(TestWorker.jobs.size).to eq(1)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sidekiq_schedulable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kevin Buchanan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sidekiq
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: parse-cron
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.4
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.1.4
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: timecop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.8.0
|
69
|
+
description: Schedule Cron style Sidekiq jobs
|
70
|
+
email:
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- ".gitignore"
|
76
|
+
- Gemfile
|
77
|
+
- README.md
|
78
|
+
- lib/sidekiq/schedulable.rb
|
79
|
+
- lib/sidekiq_schedulable.rb
|
80
|
+
- lib/sidekiq_schedulable/middleware/client.rb
|
81
|
+
- lib/sidekiq_schedulable/middleware/server.rb
|
82
|
+
- lib/sidekiq_schedulable/schedule.rb
|
83
|
+
- lib/sidekiq_schedulable/startup.rb
|
84
|
+
- lib/sidekiq_schedulable/version.rb
|
85
|
+
- sidekiq_schedulable.gemspec
|
86
|
+
- spec/sidekiq_schedulable_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
homepage: https://github.com/kevinbuch/sidekiq_schedulable
|
89
|
+
licenses:
|
90
|
+
- MIT
|
91
|
+
metadata: {}
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 2.4.5
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: Scheduled Sidekiq jobs
|
112
|
+
test_files: []
|