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 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
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
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,9 @@
1
+ require 'parse-cron'
2
+
3
+ module SidekiqSchedulable
4
+ module Schedule
5
+ def self.next_time(schedule)
6
+ CronParser.new(schedule).next(Time.now)
7
+ end
8
+ end
9
+ 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,3 @@
1
+ module SidekiqSchedulable
2
+ VERSION = '0.0.1'
3
+ 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
@@ -0,0 +1,5 @@
1
+ require 'rspec'
2
+
3
+ RSpec.configure do |config|
4
+ config.order = :random
5
+ end
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: []