sidekiq-promise 0.1.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 +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/Guardfile +14 -0
- data/LICENSE.txt +22 -0
- data/README.md +82 -0
- data/Rakefile +6 -0
- data/lib/sidekiq/promise/client_middleware.rb +12 -0
- data/lib/sidekiq/promise/middleware.rb +30 -0
- data/lib/sidekiq/promise/server_middleware.rb +16 -0
- data/lib/sidekiq/promise/version.rb +5 -0
- data/lib/sidekiq/promise/worker.rb +74 -0
- data/lib/sidekiq/promise.rb +46 -0
- data/sidekiq-promise.gemspec +29 -0
- data/spec/acceptance/completing_job_spec.rb +25 -0
- data/spec/acceptance/crashing_job_spec.rb +25 -0
- data/spec/acceptance/failing_job_spec.rb +26 -0
- data/spec/acceptance/promising_job_spec.rb +26 -0
- data/spec/lib/sidekiq/promise/client_middleware_spec.rb +16 -0
- data/spec/lib/sidekiq/promise/middleware_spec.rb +43 -0
- data/spec/lib/sidekiq/promise/server_middleware_spec.rb +29 -0
- data/spec/lib/sidekiq/promise_spec.rb +5 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/spec_server.rb +2 -0
- data/spec/support/context_helpers.rb +19 -0
- data/spec/support/mock_client_pool.rb +11 -0
- data/spec/support/sidekiq_helpers.rb +25 -0
- data/spec/workers/crashy_worker.rb +9 -0
- data/spec/workers/promising_worker.rb +11 -0
- data/spec/workers/raisey_worker.rb +10 -0
- data/spec/workers/sleepy_worker.rb +8 -0
- metadata +232 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 42bd79021c80180e745f9955f20d79676cec7a0a
|
4
|
+
data.tar.gz: c83c3a33895da56df06b0d7e59bec12a60dd431d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5fae2380872872ed025174c8283d4673dee9454a67a60e7d6716e760cf1344b3e6f5df0d2e62bf64d17975a7e5a6b16c81a0b855d7bd2e534a80616a2b2ad1b5
|
7
|
+
data.tar.gz: 110ae879d59744fd1a21ffbf1dbdf034d243901348ab9877b21a4358c759bc2ab3b816e18438d16f290a79f9a802910d6b84ea54736b33ba0cc5ab94d5ba4e57
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard :bundler do
|
5
|
+
watch('Gemfile')
|
6
|
+
watch(/^.+\.gemspec/)
|
7
|
+
end
|
8
|
+
|
9
|
+
guard :rspec do
|
10
|
+
watch(%r{^spec/.+_spec\.rb$})
|
11
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
12
|
+
watch('spec/spec_helper.rb') { "spec" }
|
13
|
+
end
|
14
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 James Harton
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# Sidekiq::Promise
|
2
|
+
|
3
|
+
`Sidekiq::Promise` turns Sidekiq workers into asynchronous promises using
|
4
|
+
[MrDarcy](https://github.com/jamesotron/MrDarcy).
|
5
|
+
|
6
|
+
[](https://travis-ci.org/jamesotron/sidekick-promise)
|
7
|
+
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'sidekiq-promise'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install sidekiq-promise
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
In your worker classes, you can now simply include `Sidekiq::Promise`:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
class HardWorker
|
29
|
+
include Sidekiq::Promise
|
30
|
+
|
31
|
+
def perform(name, count)
|
32
|
+
puts 'Doing hard work'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
In your controller or model you can call: `HardWorker.as_promise`
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
HardWorker.as_promise('bob', 5)
|
41
|
+
```
|
42
|
+
|
43
|
+
This will return a promise which will not resolve until the job is successfully
|
44
|
+
completed.
|
45
|
+
|
46
|
+
*WARNING* `Sidekiq::Promise` disables retries, so your job, if it fails will
|
47
|
+
reject it's promise and Sidekiq will not retry it.
|
48
|
+
|
49
|
+
### Why promises you say?
|
50
|
+
|
51
|
+
Because promises have [amazing chaining properties](https://github.com/jamesotron/MrDarcy#key-points-to-know-about-promises)
|
52
|
+
you can use them to build interesting and complicated workflows, eg:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
class ProcessWorker
|
56
|
+
include Sidekiq::Promise
|
57
|
+
|
58
|
+
def perform file_to_process
|
59
|
+
UnzipWorker.as_promise(file_to_process).then do |dir|
|
60
|
+
MrDarcy.all_promises do
|
61
|
+
dir.entries.map do |file|
|
62
|
+
ImageThumbnailWorker.as_promise(file)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end.then do
|
66
|
+
UserNotificationMailer.all_images_processed
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
In the above case, we use a worker to unzip a file full of images, then when
|
73
|
+
unzipped it simultaneously resizes all the images to thumbnail size, then
|
74
|
+
notifies the user that the processing is complete.
|
75
|
+
|
76
|
+
## Contributing
|
77
|
+
|
78
|
+
1. Fork it ( https://github.com/[my-github-username]/sidekiq-promise/fork )
|
79
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
80
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
81
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
82
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Promise
|
3
|
+
class Middleware
|
4
|
+
|
5
|
+
CHANNEL = '/sidekiq_jobs'
|
6
|
+
|
7
|
+
def job_enqueued job, redis_pool=Sidekiq.redis_pool
|
8
|
+
publish_message redis_pool, status: 'enqueued', job: job, jid: job['jid']
|
9
|
+
end
|
10
|
+
|
11
|
+
def job_dequeued job, redis_pool=Sidekiq.redis_pool
|
12
|
+
publish_message redis_pool, status: 'dequeued', job: job, jid: job['jid']
|
13
|
+
end
|
14
|
+
|
15
|
+
def job_completed job, redis_pool=Sidekiq.redis_pool
|
16
|
+
publish_message redis_pool, status: 'complete', job: job, jid: job['jid']
|
17
|
+
end
|
18
|
+
|
19
|
+
def job_errored job, e, redis_pool=Sidekiq.redis_pool
|
20
|
+
publish_message redis_pool, status: 'error', job: job, exception: {class: e.class.to_s, message: e.message, backtrace: e.backtrace}, jid: job['jid']
|
21
|
+
end
|
22
|
+
|
23
|
+
def publish_message redis_pool, message
|
24
|
+
redis_pool.with do |redis|
|
25
|
+
redis.publish CHANNEL, message.to_json
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Promise
|
3
|
+
class Worker < ::MrDarcy::Promise::Celluloid
|
4
|
+
|
5
|
+
attr_accessor :jid
|
6
|
+
|
7
|
+
def initialize worker_klass, *args
|
8
|
+
@worker_klass = worker_klass
|
9
|
+
@args = args
|
10
|
+
|
11
|
+
this = self
|
12
|
+
block = proc do
|
13
|
+
this.send :subscribe
|
14
|
+
end
|
15
|
+
super block
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def evaluate_promise &block
|
21
|
+
begin
|
22
|
+
block.call ::MrDarcy::Promise::DSL.new(self)
|
23
|
+
rescue Exception => e
|
24
|
+
reject e
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def subscribe
|
29
|
+
@redis = Sidekiq.redis_pool.checkout
|
30
|
+
@redis.subscribe ::Sidekiq::Promise::Middleware::CHANNEL do |on|
|
31
|
+
on.subscribe { queue_job }
|
32
|
+
on.message do |channel,message|
|
33
|
+
message = JSON.parse(message)
|
34
|
+
process_message message if applicable? message
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def unsubscribe
|
40
|
+
@redis.unsubscribe
|
41
|
+
Sidekiq.redis_pool.checkin
|
42
|
+
end
|
43
|
+
|
44
|
+
def queue_job
|
45
|
+
future = ::Celluloid::Future.new do
|
46
|
+
@worker_klass.perform_async *@args
|
47
|
+
end
|
48
|
+
@jid = future.value
|
49
|
+
end
|
50
|
+
|
51
|
+
def applicable? message
|
52
|
+
message['jid'] == jid
|
53
|
+
end
|
54
|
+
|
55
|
+
def process_message message
|
56
|
+
send "process_#{message['status']}_message", message
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_complete_message message
|
60
|
+
unsubscribe
|
61
|
+
resolve message['job']
|
62
|
+
end
|
63
|
+
|
64
|
+
def process_error_message message
|
65
|
+
unsubscribe
|
66
|
+
reject message['exception']
|
67
|
+
end
|
68
|
+
|
69
|
+
def noop *args; end
|
70
|
+
alias process_dequeued_message noop
|
71
|
+
alias process_enqueued_message noop
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "sidekiq/promise/version"
|
2
|
+
require 'sidekiq'
|
3
|
+
require 'json'
|
4
|
+
require 'mr_darcy'
|
5
|
+
require 'sidekiq/promise/middleware'
|
6
|
+
require 'sidekiq/promise/client_middleware'
|
7
|
+
require 'sidekiq/promise/server_middleware'
|
8
|
+
require 'sidekiq/promise/worker'
|
9
|
+
|
10
|
+
|
11
|
+
module Sidekiq
|
12
|
+
module Promise
|
13
|
+
def self.included(base)
|
14
|
+
base.send :include, Sidekiq::Worker unless base.ancestors.member? Sidekiq::Worker
|
15
|
+
base.extend(ClassMethods)
|
16
|
+
base.send :sidekiq_options, retry: false
|
17
|
+
unless MrDarcy.driver == :celluloid
|
18
|
+
STDOUT.puts "Switched your MrDarcy driver to Celluloid - it was #{MrDarcy.driver}"
|
19
|
+
MrDarcy.driver = :celluloid
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassMethods
|
24
|
+
def as_promise(*args)
|
25
|
+
::Sidekiq::Promise::Worker.new self, *args
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module_function
|
30
|
+
def enable_middleware!
|
31
|
+
raise RuntimeError, "WARNING: Unable to configure required middleware. sidekiq-promise won't work :(" unless Sidekiq.respond_to? :configure_server
|
32
|
+
Sidekiq.configure_server do |config|
|
33
|
+
config.server_middleware do |chain|
|
34
|
+
chain.add Sidekiq::Promise::ServerMiddleware
|
35
|
+
end
|
36
|
+
end
|
37
|
+
Sidekiq.configure_client do |config|
|
38
|
+
config.client_middleware do |chain|
|
39
|
+
chain.add Sidekiq::Promise::ClientMiddleware
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Sidekiq::Promise.enable_middleware!
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sidekiq/promise/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sidekiq-promise"
|
8
|
+
spec.version = Sidekiq::Promise::VERSION
|
9
|
+
spec.authors = ["James Harton"]
|
10
|
+
spec.email = ["james@resistor.io"]
|
11
|
+
spec.summary = %q{Wrap Sidekiq jobs in promises}
|
12
|
+
spec.description = %q{Treat Sidekiq jobs as asynchronous promises.}
|
13
|
+
spec.homepage = "https://github.com/jamesotron/sidekiq-promise"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
+
%w| rake rspec guard guard-rspec guard-bundler terminal-notifier-guard
|
23
|
+
pry |.each do |gem|
|
24
|
+
spec.add_development_dependency gem
|
25
|
+
end
|
26
|
+
|
27
|
+
spec.add_dependency 'sidekiq', '~> 3.0.1'
|
28
|
+
spec.add_dependency 'mr_darcy', '>= 0.3.0'
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Completing job as promise' do
|
4
|
+
before(:all) { start_worker }
|
5
|
+
after(:all) { kill_worker }
|
6
|
+
after { clear_jobs }
|
7
|
+
|
8
|
+
let(:promise) { SleepyWorker.as_promise(0.1) }
|
9
|
+
subject { promise }
|
10
|
+
|
11
|
+
its(:final) { should be_resolved }
|
12
|
+
its(:final) { should_not be_rejected }
|
13
|
+
|
14
|
+
describe '#then' do
|
15
|
+
it 'yields' do
|
16
|
+
expect { |b| promise.final.then(&b) }.to yield_control
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#fail' do
|
21
|
+
it 'does not yield' do
|
22
|
+
expect { |b| promise.final.fail(&b) }.not_to yield_control
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Crashing job as promise' do
|
4
|
+
|
5
|
+
before { start_worker }
|
6
|
+
after { kill_worker; clear_jobs }
|
7
|
+
|
8
|
+
let(:promise) { CrashyWorker.as_promise }
|
9
|
+
subject { promise }
|
10
|
+
|
11
|
+
its(:final) { should_not be_resolved }
|
12
|
+
its(:final) { should be_rejected }
|
13
|
+
|
14
|
+
describe '#then' do
|
15
|
+
it 'does not yield' do
|
16
|
+
expect { |b| promise.final.then(&b) }.not_to yield_control
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#fail' do
|
21
|
+
it 'yields' do
|
22
|
+
expect { |b| promise.final.fail(&b) }.to yield_control
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Failing job as promise' do
|
4
|
+
before(:all) { start_worker }
|
5
|
+
after(:all) { kill_worker }
|
6
|
+
before { clear_jobs }
|
7
|
+
after { clear_jobs }
|
8
|
+
|
9
|
+
let(:promise) { RaiseyWorker.as_promise }
|
10
|
+
subject { promise }
|
11
|
+
|
12
|
+
its(:final) { should_not be_resolved }
|
13
|
+
its(:final) { should be_rejected }
|
14
|
+
|
15
|
+
describe '#then' do
|
16
|
+
it 'does not yield' do
|
17
|
+
expect { |b| promise.final.then(&b) }.not_to yield_control
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#fail' do
|
22
|
+
it 'yields' do
|
23
|
+
expect { |b| promise.final.fail(&b) }.to yield_control
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Promising job as promise' do
|
4
|
+
before(:all) { start_worker }
|
5
|
+
after(:all) { kill_worker }
|
6
|
+
before { clear_jobs }
|
7
|
+
after { clear_jobs }
|
8
|
+
|
9
|
+
let(:promise) { PromisingWorker.as_promise }
|
10
|
+
subject { promise }
|
11
|
+
|
12
|
+
its(:final) { should be_resolved }
|
13
|
+
its(:final) { should_not be_rejected }
|
14
|
+
|
15
|
+
describe '#then' do
|
16
|
+
it 'yields' do
|
17
|
+
expect { |b| promise.final.then(&b) }.to yield_control
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#fail' do
|
22
|
+
it 'does not yield' do
|
23
|
+
expect { |b| promise.final.fail(&b) }.not_to yield_control
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sidekiq::Promise::ClientMiddleware do
|
4
|
+
let(:worker_class) { Class.new }
|
5
|
+
let(:job) { double :job }
|
6
|
+
let(:queue) { 'default' }
|
7
|
+
let(:redis_pool) { double :redis_pool }
|
8
|
+
let(:middleware) { described_class.new }
|
9
|
+
|
10
|
+
describe '#call' do
|
11
|
+
it 'sends a message about enqueuing the job, then yields' do
|
12
|
+
expect(middleware).to receive(:job_enqueued).with(job, redis_pool)
|
13
|
+
expect { |b| middleware.call(worker_class, job, queue, redis_pool, &b) }.to yield_control
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sidekiq::Promise::Middleware do
|
4
|
+
let(:redis_client) { double :redis_client }
|
5
|
+
let(:redis_pool) { MockClientPool.new redis_client }
|
6
|
+
let(:middleware) { described_class.new }
|
7
|
+
|
8
|
+
describe '#job_enqueued' do
|
9
|
+
it 'delegates to #publish_message' do
|
10
|
+
expect(middleware).to receive(:publish_message).with(redis_pool, {status: 'enqueued', job: {}, jid: nil})
|
11
|
+
middleware.job_enqueued Hash.new, redis_pool
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#job_dequeued' do
|
16
|
+
it 'delegates to #publish_message' do
|
17
|
+
expect(middleware).to receive(:publish_message).with(redis_pool, {status: 'dequeued', job: {}, jid: nil})
|
18
|
+
middleware.job_dequeued Hash.new, redis_pool
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#job_completed' do
|
23
|
+
it 'delegates to #publish_message' do
|
24
|
+
expect(middleware).to receive(:publish_message).with(redis_pool, {status: 'complete', job: {}, jid: nil})
|
25
|
+
middleware.job_completed Hash.new, redis_pool
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#job_errored' do
|
30
|
+
it 'delegates to #publish_message' do
|
31
|
+
expect(middleware).to receive(:publish_message).with(redis_pool, {status: 'error', job: {}, jid: nil, exception: {class: 'RuntimeError', message: 'fake error', backtrace: nil}})
|
32
|
+
middleware.job_errored Hash.new, RuntimeError.new('fake error'), redis_pool
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#publish_message' do
|
37
|
+
it 'sends the message to redis' do
|
38
|
+
message = {message: 'fake message'}
|
39
|
+
expect(redis_client).to receive(:publish).with('/sidekiq_jobs', message.to_json)
|
40
|
+
middleware.publish_message redis_pool, message
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sidekiq::Promise::ServerMiddleware do
|
4
|
+
let(:worker) { double :worker }
|
5
|
+
let(:job) { double :job }
|
6
|
+
let(:queue) { 'default' }
|
7
|
+
let(:middleware) { described_class.new }
|
8
|
+
|
9
|
+
describe '#call' do
|
10
|
+
When 'the job is successful' do
|
11
|
+
it 'dequeues the job, then yields, then completes' do
|
12
|
+
expect(middleware).to receive(:job_dequeued).with(job)
|
13
|
+
expect(middleware).to receive(:job_completed).with(job)
|
14
|
+
expect { |b| middleware.call(worker, job, queue, &b) }.to yield_control
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
When 'the jobs fails' do
|
19
|
+
it 'dequeues the job, then yeilds, then errors' do
|
20
|
+
exception = RuntimeError.new('test exception')
|
21
|
+
expect(middleware).to receive(:job_dequeued).with(job)
|
22
|
+
expect(middleware).to receive(:job_errored).with(job, exception)
|
23
|
+
expect do
|
24
|
+
middleware.call(worker,job,queue) { raise exception }
|
25
|
+
end.to raise_error
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'sidekiq/promise'
|
2
|
+
require 'mr_darcy'
|
3
|
+
require 'pry'
|
4
|
+
|
5
|
+
Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require f }
|
6
|
+
Dir[File.expand_path('../workers/**/*.rb', __FILE__)].each { |f| require f }
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.color_enabled = true
|
10
|
+
config.formatter = :documentation
|
11
|
+
config.extend ContextHelpers
|
12
|
+
config.include SidekiqHelpers, example_group: {
|
13
|
+
file_path: %r(spec/acceptance)
|
14
|
+
}
|
15
|
+
end
|
data/spec/spec_server.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module ContextHelpers
|
2
|
+
def When(msg=nil,&block)
|
3
|
+
context("When#{left_pad msg}", &block)
|
4
|
+
end
|
5
|
+
|
6
|
+
def Otherwise(msg=nil,&block)
|
7
|
+
context("Otherwise#{left_pad msg}", &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
def And(msg=nil,&block)
|
11
|
+
context("And#{left_pad msg}", &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def left_pad(msg)
|
17
|
+
msg ? " #{msg}" : ""
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'sidekiq/api'
|
2
|
+
|
3
|
+
module SidekiqHelpers
|
4
|
+
def start_worker
|
5
|
+
return if @worker_pid
|
6
|
+
server_path = File.expand_path('../../spec_server.rb', __FILE__)
|
7
|
+
@worker_pid = Process.spawn("bundle exec sidekiq -t 0 -r #{server_path}")
|
8
|
+
end
|
9
|
+
|
10
|
+
def kill_worker
|
11
|
+
return unless @worker_pid
|
12
|
+
Process.kill('TERM', @worker_pid)
|
13
|
+
Process.wait(@worker_pid)
|
14
|
+
rescue Errno::ESRCH
|
15
|
+
ensure
|
16
|
+
@worker_pid = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear_jobs
|
20
|
+
Sidekiq::Queue.new.clear
|
21
|
+
Sidekiq::RetrySet.new.clear
|
22
|
+
Sidekiq::ScheduledSet.new.clear
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sidekiq-promise
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Harton
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: guard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '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'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard-rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard-bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: terminal-notifier-guard
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: sidekiq
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ~>
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 3.0.1
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ~>
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 3.0.1
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: mr_darcy
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 0.3.0
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.3.0
|
153
|
+
description: Treat Sidekiq jobs as asynchronous promises.
|
154
|
+
email:
|
155
|
+
- james@resistor.io
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- .gitignore
|
161
|
+
- .travis.yml
|
162
|
+
- Gemfile
|
163
|
+
- Guardfile
|
164
|
+
- LICENSE.txt
|
165
|
+
- README.md
|
166
|
+
- Rakefile
|
167
|
+
- lib/sidekiq/promise.rb
|
168
|
+
- lib/sidekiq/promise/client_middleware.rb
|
169
|
+
- lib/sidekiq/promise/middleware.rb
|
170
|
+
- lib/sidekiq/promise/server_middleware.rb
|
171
|
+
- lib/sidekiq/promise/version.rb
|
172
|
+
- lib/sidekiq/promise/worker.rb
|
173
|
+
- sidekiq-promise.gemspec
|
174
|
+
- spec/acceptance/completing_job_spec.rb
|
175
|
+
- spec/acceptance/crashing_job_spec.rb
|
176
|
+
- spec/acceptance/failing_job_spec.rb
|
177
|
+
- spec/acceptance/promising_job_spec.rb
|
178
|
+
- spec/lib/sidekiq/promise/client_middleware_spec.rb
|
179
|
+
- spec/lib/sidekiq/promise/middleware_spec.rb
|
180
|
+
- spec/lib/sidekiq/promise/server_middleware_spec.rb
|
181
|
+
- spec/lib/sidekiq/promise_spec.rb
|
182
|
+
- spec/spec_helper.rb
|
183
|
+
- spec/spec_server.rb
|
184
|
+
- spec/support/context_helpers.rb
|
185
|
+
- spec/support/mock_client_pool.rb
|
186
|
+
- spec/support/sidekiq_helpers.rb
|
187
|
+
- spec/workers/crashy_worker.rb
|
188
|
+
- spec/workers/promising_worker.rb
|
189
|
+
- spec/workers/raisey_worker.rb
|
190
|
+
- spec/workers/sleepy_worker.rb
|
191
|
+
homepage: https://github.com/jamesotron/sidekiq-promise
|
192
|
+
licenses:
|
193
|
+
- MIT
|
194
|
+
metadata: {}
|
195
|
+
post_install_message:
|
196
|
+
rdoc_options: []
|
197
|
+
require_paths:
|
198
|
+
- lib
|
199
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - '>='
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: '0'
|
204
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - '>='
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
209
|
+
requirements: []
|
210
|
+
rubyforge_project:
|
211
|
+
rubygems_version: 2.2.2
|
212
|
+
signing_key:
|
213
|
+
specification_version: 4
|
214
|
+
summary: Wrap Sidekiq jobs in promises
|
215
|
+
test_files:
|
216
|
+
- spec/acceptance/completing_job_spec.rb
|
217
|
+
- spec/acceptance/crashing_job_spec.rb
|
218
|
+
- spec/acceptance/failing_job_spec.rb
|
219
|
+
- spec/acceptance/promising_job_spec.rb
|
220
|
+
- spec/lib/sidekiq/promise/client_middleware_spec.rb
|
221
|
+
- spec/lib/sidekiq/promise/middleware_spec.rb
|
222
|
+
- spec/lib/sidekiq/promise/server_middleware_spec.rb
|
223
|
+
- spec/lib/sidekiq/promise_spec.rb
|
224
|
+
- spec/spec_helper.rb
|
225
|
+
- spec/spec_server.rb
|
226
|
+
- spec/support/context_helpers.rb
|
227
|
+
- spec/support/mock_client_pool.rb
|
228
|
+
- spec/support/sidekiq_helpers.rb
|
229
|
+
- spec/workers/crashy_worker.rb
|
230
|
+
- spec/workers/promising_worker.rb
|
231
|
+
- spec/workers/raisey_worker.rb
|
232
|
+
- spec/workers/sleepy_worker.rb
|