sidekiq-resque_status 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rvmrc +1 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +66 -0
- data/Rakefile +2 -0
- data/lib/sidekiq-resque_status.rb +187 -0
- data/lib/sidekiq-resque_status/middleware/client/resque_like.rb +17 -0
- data/lib/sidekiq-resque_status/middleware/server/resque_like.rb +24 -0
- data/lib/sidekiq-resque_status/sidekiq/processor.rb +35 -0
- data/lib/sidekiq-resque_status/sidekiq_worker_with_status.rb +6 -0
- data/lib/sidekiq-resque_status/version.rb +5 -0
- data/sidekiq-resque_status.gemspec +28 -0
- data/spec/sidekiq-resque_status/test_middleware.rb +98 -0
- data/spec/sidekiq-resque_status_spec.rb +21 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/failing_job.rb +6 -0
- data/spec/support/sleeping_job.rb +6 -0
- metadata +170 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.3-p194@sidekiq
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Thomas Dmytryk
|
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,66 @@
|
|
1
|
+
# Sidekiq::ResqueStatus
|
2
|
+
|
3
|
+
Sidekiq-resque_status is a Sidekiq plug-in that will allow you to manage and check the progress of your resque jobs and sidekiq workers under the same place: the resque web-ui interface. Sidekiq and Resque are two different queuing system and depending on the type of jobs you have to process you might want to use one or the other. These two queuing system have their own web interface. This gem allow you, in case you are using both queuing system in one project, to group them under the resque web-ui.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'sidekiq-resque_status'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install sidekiq-resque_status
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
# Personalize your worker:
|
22
|
+
|
23
|
+
To add Sidekiq worker to your resque web-ui you just need inherit your worker class with SidekiqWorkerWithStatus
|
24
|
+
|
25
|
+
class SleepingJob < SidekiqWorkerWithStatus
|
26
|
+
def perform(*args)
|
27
|
+
sleep args[0] || 0.1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Set up your Sidekiq connection base on your Resque one
|
32
|
+
|
33
|
+
In order for sidekiq-resque_status to work properly you need to tell sidekiq to use the same connection as Resque (same namespace, same url).
|
34
|
+
You can do so by creating a config file (such as sidekiq_config.rb) and doing:
|
35
|
+
|
36
|
+
Sidekiq.configure_server do |config|
|
37
|
+
config.redis = {:namespace => Resque.redis.namespace, :url => url }
|
38
|
+
end
|
39
|
+
|
40
|
+
Sidekiq.configure_client do |config|
|
41
|
+
config.redis = { :namespace => Resque.redis.namespace, :url => url }
|
42
|
+
end
|
43
|
+
|
44
|
+
# Add the sidekiq-resque_status middleware to the Sidekiq server and client middleware
|
45
|
+
|
46
|
+
Sidekiq.configure_server do |config|
|
47
|
+
config.server_middleware do |chain|
|
48
|
+
chain.add Sidekiq::Status::ServerMiddleware
|
49
|
+
chain.add Sidekiq::Middleware::Server::Stats::ResqueLike
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Sidekiq.configure_client do |config|
|
54
|
+
config.client_middleware do |chain|
|
55
|
+
chain.add Sidekiq::Status::ClientMiddleware
|
56
|
+
chain.add Sidekiq::Middleware::Client::Stats::ResqueLike
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
## Contributing
|
61
|
+
|
62
|
+
1. Fork it
|
63
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
64
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
65
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
66
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
require 'sidekiq-status'
|
3
|
+
require 'sidekiq-resque_status/version'
|
4
|
+
require 'sidekiq-resque_status/sidekiq_worker_with_status'
|
5
|
+
|
6
|
+
Dir["#{File.dirname(__FILE__)}/sidekiq-resque_status/middleware/**/*.rb"].each { |f| require f }
|
7
|
+
Dir["#{File.dirname(__FILE__)}/sidekiq-resque_status/sidekiq/**/*.rb"].each { |f| require f }
|
8
|
+
|
9
|
+
module Sidekiq
|
10
|
+
module ResqueStatus
|
11
|
+
|
12
|
+
###
|
13
|
+
# => This method will be called by the client middleware before enqueing a job.
|
14
|
+
# => It stores information on the current job.
|
15
|
+
# => These information will be display by resque web-ui each time a user is browsing:
|
16
|
+
# - the statuses page (provided by resque-status)
|
17
|
+
# - the job_stats page (provided by resque-job-stats)
|
18
|
+
###
|
19
|
+
def enqueue_job(worker, msg, queue)
|
20
|
+
now = Time.now.utc + 1
|
21
|
+
|
22
|
+
# Resque Job Stats equivalent
|
23
|
+
increment_stat("stats:jobs:#{worker.name}:enqueued", now)
|
24
|
+
|
25
|
+
# Status set to queued
|
26
|
+
status_hash = { :time => now.to_i, :class => worker.name, :retry => false, :name => "#{worker.name}(#{msg['args']})", :status => "queued", :uuid => msg['jid'], :args => msg['args']}
|
27
|
+
update_status("status:#{msg['jid']}", "queued", status_hash)
|
28
|
+
|
29
|
+
# Add the job id to the _statuses key
|
30
|
+
redis.zadd("_statuses", now.to_i, msg['jid'])
|
31
|
+
end
|
32
|
+
|
33
|
+
###
|
34
|
+
# => This method will be called by the server middleware before processing a job.
|
35
|
+
# => It makes sure we are not loosing any information at the beggining of the process.
|
36
|
+
# => It updates information on the current job.
|
37
|
+
# => These information will be display by resque web-ui each time a user is browsing:
|
38
|
+
# - the statuses page (provided by resque-status)
|
39
|
+
# - the job_stats page (provided by resque-job-stats)
|
40
|
+
###
|
41
|
+
def job_in_progress(worker, msg, queue)
|
42
|
+
# When resqueue web re-enqueue a job we need to make sure worker.jid and msg[jid] are defined
|
43
|
+
worker.jid ||= msg['jid'] ||= msg['args'].first['jid'] if msg['args'] && msg['args'].is_a?(Array)
|
44
|
+
|
45
|
+
# Set status to working
|
46
|
+
status_hash = set_missing_values(worker, msg, queue)
|
47
|
+
status_hash = update_status("status:#{msg['jid']}", "working", status_hash)
|
48
|
+
end
|
49
|
+
|
50
|
+
###
|
51
|
+
# => This method will be called by the server middleware after processing a job.
|
52
|
+
# => It adds a description of the processed jobs.
|
53
|
+
# => It updates information on the current job.
|
54
|
+
# => These information will be display by resque web-ui each time a user is browsing:
|
55
|
+
# - the statuses page (provided by resque-status)
|
56
|
+
# - the job_stats page (provided by resque-job-stats)
|
57
|
+
# - the queues page (provided by resque-web)
|
58
|
+
###
|
59
|
+
def job_completed(worker, msg, queue, duration = 0)
|
60
|
+
status_hash = complete_options(worker.to_process || 1, worker.processed || 1, duration, worker.description)
|
61
|
+
status_hash = set_missing_values(worker, msg, queue, status_hash)
|
62
|
+
|
63
|
+
# Status set to completed
|
64
|
+
hash = update_status("status:#{msg['jid']}", "completed", status_hash) || {}
|
65
|
+
time = hash["time"] || hash["run_at"]
|
66
|
+
now = time ? Time.at(time.to_i) : Time.now.utc
|
67
|
+
|
68
|
+
# Resque job Stats equivalent
|
69
|
+
increment_stat("stats:jobs:#{msg['jid']}:timeseries:performed", now)
|
70
|
+
increment_stat("stats:jobs:#{worker.class.name}:performed", now)
|
71
|
+
|
72
|
+
# Set duration
|
73
|
+
redis.rpush("stats:jobs:#{worker.class.name}:duration", duration)
|
74
|
+
redis.rpush("stats:jobs:#{msg['jid']}:duration", duration)
|
75
|
+
|
76
|
+
# remove job from the queue tab
|
77
|
+
redis.lpop("queue:#{queue}")
|
78
|
+
end
|
79
|
+
|
80
|
+
###
|
81
|
+
# => This method will be called by the server middleware each time a job failed.
|
82
|
+
# => It adds a complete description of the failure.
|
83
|
+
# => It updates information on the current job.
|
84
|
+
# => It makes sure the job can be replay.
|
85
|
+
# => These information will be display by resque web-ui each time a user is browsing:
|
86
|
+
# - the failed page (provided by resque-web)
|
87
|
+
###
|
88
|
+
def job_failed(worker, msg, queue, error)
|
89
|
+
hash = merge_value("status:#{msg['jid']}", {"status" => "failed", "message" => error.message})
|
90
|
+
update_status("status:#{msg['jid']}", "failed", hash)
|
91
|
+
|
92
|
+
# pass the jid into args hash to replay the job
|
93
|
+
args = msg['args'].is_a?(Array) && msg['args'].first.is_a?(Hash) ? [msg['args'].first.merge({'jid' => msg['jid']})] : msg['args']
|
94
|
+
|
95
|
+
failed_message = {
|
96
|
+
:failed_at => Time.now.rfc2822,
|
97
|
+
:payload => {"class" => worker.class.name, "args" => args},
|
98
|
+
:class => worker.class.name,
|
99
|
+
:exception => error.class.name,
|
100
|
+
:error => error.message,
|
101
|
+
:backtrace => error.backtrace,
|
102
|
+
:worker => queue,
|
103
|
+
:queue => queue,
|
104
|
+
:args => args,
|
105
|
+
:jid => msg['jid']
|
106
|
+
}
|
107
|
+
# Push the failed information into redis
|
108
|
+
redis.rpush('failed', MultiJson.dump(failed_message))
|
109
|
+
|
110
|
+
# Increment failed statistics for job Stats
|
111
|
+
increment_stat("stats:jobs:#{worker.class.name}:failed", Time.now)
|
112
|
+
increment_expire_key("stat:failed")
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
###
|
118
|
+
# => Return the redis connection
|
119
|
+
###
|
120
|
+
def redis
|
121
|
+
@redis ||= Sidekiq.redis {|conn| conn}
|
122
|
+
end
|
123
|
+
|
124
|
+
###
|
125
|
+
# => Return hash containing some statistics about the processed job
|
126
|
+
###
|
127
|
+
def complete_options(total_to_process, total_processed, duration = 0, message = nil)
|
128
|
+
average = (duration/total_processed rescue 0).round(1)
|
129
|
+
time = duration.round(1)
|
130
|
+
|
131
|
+
message ||= "processed #{total_processed} in A: #{average} T: #{time}"
|
132
|
+
{"status" => "completed", :total => total_to_process, :num => total_processed, :message => message}
|
133
|
+
end
|
134
|
+
|
135
|
+
###
|
136
|
+
# => Increment a given key and set an expiration date
|
137
|
+
###
|
138
|
+
def increment_expire_key(key, duration = nil)
|
139
|
+
redis.expire(key, duration) if duration
|
140
|
+
redis.incr(key)
|
141
|
+
end
|
142
|
+
|
143
|
+
###
|
144
|
+
# => Build Hourly, Daily and Global statistics that will be used by resque-job-stats
|
145
|
+
###
|
146
|
+
def increment_stat(key, now)
|
147
|
+
# Increment global stats
|
148
|
+
increment_expire_key(key)
|
149
|
+
|
150
|
+
# Increment hourly stats
|
151
|
+
increment_expire_key(key + ":#{now.hour}:#{now.min}:#{now.sec}", 3660)
|
152
|
+
|
153
|
+
# Increment daily stats
|
154
|
+
increment_expire_key(key + ":#{now.hour}:#{now.min}", 900000)
|
155
|
+
end
|
156
|
+
|
157
|
+
###
|
158
|
+
# => Update the status of a job and add more information to it if requested
|
159
|
+
###
|
160
|
+
def update_status(key, status, hash = nil)
|
161
|
+
status_hash = merge_value(key, {"status" => status}) || {}
|
162
|
+
status_hash.merge!(hash) if hash
|
163
|
+
|
164
|
+
redis.set(key, MultiJson.dump(status_hash))
|
165
|
+
redis.expire(key, 260000)
|
166
|
+
status_hash
|
167
|
+
end
|
168
|
+
|
169
|
+
###
|
170
|
+
# => Get the value of a key and merge it
|
171
|
+
###
|
172
|
+
def merge_value(key,hash)
|
173
|
+
value = redis.get(key)
|
174
|
+
MultiJson.load(value).merge(hash) if value
|
175
|
+
end
|
176
|
+
|
177
|
+
###
|
178
|
+
# => Ensure we always get track of the important informations concerning the worker
|
179
|
+
###
|
180
|
+
def set_missing_values(worker, msg, queue, status_hash = {})
|
181
|
+
status_hash['jid'] = msg['jid'] if status_hash['jid'].nil?
|
182
|
+
status_hash['queue'] = queue if status_hash['queue'].nil?
|
183
|
+
status_hash['class'] = worker.class.name if status_hash['class'].nil?
|
184
|
+
status_hash
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Middleware
|
3
|
+
module Client
|
4
|
+
module Stats
|
5
|
+
class ResqueLike
|
6
|
+
include Sidekiq::ResqueStatus
|
7
|
+
# Store information on the current enqueued job into redis
|
8
|
+
|
9
|
+
def call(worker, msg, queue)
|
10
|
+
enqueue_job(worker, msg, queue)
|
11
|
+
yield
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module Middleware
|
3
|
+
module Server
|
4
|
+
module Stats
|
5
|
+
class ResqueLike
|
6
|
+
include Sidekiq::ResqueStatus
|
7
|
+
# Update the status, and add other information (such as the job description) into redis
|
8
|
+
|
9
|
+
def call(worker, msg, queue)
|
10
|
+
begin
|
11
|
+
job_in_progress(worker, msg, queue)
|
12
|
+
start_time = Time.now
|
13
|
+
yield
|
14
|
+
job_completed(worker, msg, queue, Time.now-start_time)
|
15
|
+
rescue Exception => error
|
16
|
+
job_failed(worker, msg, queue, error)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
|
3
|
+
# Monkey patch to overide the run_at attribute (Time instead of unix timestamp)
|
4
|
+
# and remove the failed key incrementation
|
5
|
+
class Processor
|
6
|
+
private
|
7
|
+
def stats(worker, msg, queue)
|
8
|
+
redis do |conn|
|
9
|
+
conn.multi do
|
10
|
+
conn.sadd('workers', self)
|
11
|
+
conn.setex("worker:#{self}:started", EXPIRY, Time.now.to_s)
|
12
|
+
hash = {:queue => queue, :payload => msg, :run_at => Time.now }
|
13
|
+
conn.setex("worker:#{self}", EXPIRY, Sidekiq.dump_json(hash))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
dying = false
|
18
|
+
begin
|
19
|
+
yield
|
20
|
+
rescue Exception
|
21
|
+
dying = true
|
22
|
+
raise
|
23
|
+
ensure
|
24
|
+
redis do |conn|
|
25
|
+
conn.multi do
|
26
|
+
conn.srem("workers", self)
|
27
|
+
conn.del("worker:#{self}")
|
28
|
+
conn.del("worker:#{self}:started")
|
29
|
+
conn.incrby("stat:processed", 1)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/sidekiq-resque_status/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ['Thomas Dmytryk']
|
6
|
+
gem.email = ['thomas@fanhattan.com', 'thomas.dmytryk@supinfo.com']
|
7
|
+
gem.description = %q{sidekiq-resque_status is a Sidekiq plugin that allows to see statuses of Sidekiq workers using the Resque web interface}
|
8
|
+
gem.summary = %q{sidekiq-resque_status is an extension to the Sidekiq queue system. It has been created to centralize Resque jobs statuses and Sidekiq workers statuses inside the resque-web interface.}
|
9
|
+
gem.homepage = ''
|
10
|
+
gem.license = 'MIT'
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = 'sidekiq-resque_status'
|
16
|
+
gem.require_paths = ['lib']
|
17
|
+
gem.version = Sidekiq::ResqueStatus::VERSION
|
18
|
+
|
19
|
+
gem.add_runtime_dependency("activesupport", '~> 3.2.11')
|
20
|
+
|
21
|
+
gem.add_dependency 'sidekiq', '~> 2.6.4'
|
22
|
+
gem.add_dependency 'sidekiq-status'
|
23
|
+
gem.add_dependency 'multi_json', '~> 1'
|
24
|
+
|
25
|
+
|
26
|
+
gem.add_development_dependency 'rspec'
|
27
|
+
gem.add_development_dependency 'minitest', '~> 4'
|
28
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'minitest/unit'
|
3
|
+
require 'minitest/pride'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
require 'sidekiq'
|
7
|
+
require 'sidekiq/fetch'
|
8
|
+
require 'sidekiq/redis_connection'
|
9
|
+
require 'sidekiq/processor'
|
10
|
+
|
11
|
+
|
12
|
+
REDIS = Sidekiq::RedisConnection.create(:url => "redis://localhost/15", :namespace => 'test')
|
13
|
+
|
14
|
+
class TestMiddleware < MiniTest::Unit::TestCase
|
15
|
+
describe 'middleware chain' do
|
16
|
+
before do
|
17
|
+
$errors = []
|
18
|
+
Sidekiq.redis = REDIS
|
19
|
+
Sidekiq.redis { |conn| conn.flushall }
|
20
|
+
sleep 0.1
|
21
|
+
end
|
22
|
+
|
23
|
+
let!(:redis) { Sidekiq.redis { |conn| conn } }
|
24
|
+
let!(:job_id) { '987654321' }
|
25
|
+
|
26
|
+
def process_job(msg)
|
27
|
+
boss = MiniTest::Mock.new
|
28
|
+
processor = Sidekiq::Processor.new(boss)
|
29
|
+
actor = MiniTest::Mock.new
|
30
|
+
actor.expect(:processor_done, nil, [processor])
|
31
|
+
boss.expect(:async, actor, [])
|
32
|
+
processor.process(Sidekiq::BasicFetch::UnitOfWork.new('queue:default', msg))
|
33
|
+
end
|
34
|
+
|
35
|
+
Sidekiq.server_middleware do |chain|
|
36
|
+
# should only add once, second should be ignored
|
37
|
+
chain.add Sidekiq::Status::ServerMiddleware
|
38
|
+
chain.add Sidekiq::Middleware::Server::Stats::ResqueLike
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "Processing a valid job" do
|
42
|
+
it "should add completed status information using jid" do
|
43
|
+
msg = '{ "class": "' + SleepingJob.name + '", "args": [null], "jid": "' + job_id + '" }'
|
44
|
+
process_job(msg)
|
45
|
+
|
46
|
+
status = redis.get("status:#{job_id}")
|
47
|
+
status.should_not be_nil
|
48
|
+
status = MultiJson.load(status)
|
49
|
+
|
50
|
+
status['status'].should == 'completed'
|
51
|
+
status['class'].should == SleepingJob.name
|
52
|
+
status['queue'].should == 'default'
|
53
|
+
status['jid'].should == job_id
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "Processing a failing job" do
|
58
|
+
let!(:msg) { '{ "class": "' + FailingJob.name + '", "args": [0], "jid": "' + job_id + '" }'}
|
59
|
+
|
60
|
+
it "should update job status to failed status" do
|
61
|
+
process_job(msg)
|
62
|
+
|
63
|
+
status = redis.get("status:#{job_id}")
|
64
|
+
status.should_not be_nil
|
65
|
+
status = MultiJson.load(status)
|
66
|
+
|
67
|
+
status['status'].should == 'failed'
|
68
|
+
status['class'].should == FailingJob.name
|
69
|
+
status['jid'].should == job_id
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should add failed information" do
|
73
|
+
process_job(msg)
|
74
|
+
|
75
|
+
detailed_status = redis.lindex('failed', 0)
|
76
|
+
detailed_status.should_not be_nil
|
77
|
+
detailed_status = MultiJson.load(detailed_status)
|
78
|
+
|
79
|
+
detailed_status['failed_at'].should == Time.now.rfc2822
|
80
|
+
detailed_status['class'].should == FailingJob.name
|
81
|
+
detailed_status['jid'].should == job_id
|
82
|
+
detailed_status['args'].should == [0]
|
83
|
+
detailed_status['exception'].should == StandardError.name
|
84
|
+
detailed_status['error'].should == "This job is supposed to failed."
|
85
|
+
detailed_status['backtrace'].should_not be_nil
|
86
|
+
detailed_status['payload'].should == { 'class' => FailingJob.name, 'args' => [0] }
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should increment the number of failed jobs" do
|
90
|
+
nb_failed, nb_job_failed = redis.get("stat:failed").to_i, redis.get("stats:jobs:#{FailingJob.name}:failed").to_i
|
91
|
+
process_job(msg)
|
92
|
+
|
93
|
+
redis.get("stat:failed").to_i.should == nb_failed + 1
|
94
|
+
redis.get("stats:jobs:#{FailingJob.name}:failed").to_i == nb_job_failed + 1
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sidekiq/testing/inline'
|
3
|
+
|
4
|
+
describe Sidekiq::ResqueStatus do
|
5
|
+
|
6
|
+
let!(:redis) { Sidekiq.redis { |conn| conn } }
|
7
|
+
|
8
|
+
# Clean Redis before each test
|
9
|
+
# Seems like flushall has no effect on recently published messages,
|
10
|
+
# so we should wait till they expire
|
11
|
+
before { redis.flushall; sleep 0.1 }
|
12
|
+
|
13
|
+
describe "Enqueuing a job" do
|
14
|
+
it "should increment the number of enqueued jobs" do
|
15
|
+
nb_enqueued = redis.get("stats:jobs:#{SleepingJob.name}:enqueued").to_i
|
16
|
+
SleepingJob.perform_async(1)
|
17
|
+
|
18
|
+
redis.get("stats:jobs:#{SleepingJob.name}:enqueued").to_i.should == nb_enqueued + 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'sidekiq-resque_status'
|
2
|
+
Dir["#{File.dirname(__FILE__)}/support/*.rb"].each { |f| require f }
|
3
|
+
|
4
|
+
# Add Sidekiq-status and sidekiq-resque_status to the server and client middleware
|
5
|
+
Sidekiq.configure_server do |config|
|
6
|
+
config.server_middleware do |chain|
|
7
|
+
chain.add Sidekiq::Status::ServerMiddleware
|
8
|
+
chain.add Sidekiq::Middleware::Server::Stats::ResqueLike
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Sidekiq.configure_client do |config|
|
13
|
+
config.client_middleware do |chain|
|
14
|
+
chain.add Sidekiq::Status::ClientMiddleware
|
15
|
+
chain.add Sidekiq::Middleware::Client::Stats::ResqueLike
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sidekiq-resque_status
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas Dmytryk
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.11
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.11
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: sidekiq
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.6.4
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.6.4
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: sidekiq-status
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: multi_json
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '1'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: minitest
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '4'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '4'
|
110
|
+
description: sidekiq-resque_status is a Sidekiq plugin that allows to see statuses
|
111
|
+
of Sidekiq workers using the Resque web interface
|
112
|
+
email:
|
113
|
+
- thomas@fanhattan.com
|
114
|
+
- thomas.dmytryk@supinfo.com
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- .gitignore
|
120
|
+
- .rvmrc
|
121
|
+
- CHANGELOG.md
|
122
|
+
- Gemfile
|
123
|
+
- LICENSE
|
124
|
+
- README.md
|
125
|
+
- Rakefile
|
126
|
+
- lib/sidekiq-resque_status.rb
|
127
|
+
- lib/sidekiq-resque_status/middleware/client/resque_like.rb
|
128
|
+
- lib/sidekiq-resque_status/middleware/server/resque_like.rb
|
129
|
+
- lib/sidekiq-resque_status/sidekiq/processor.rb
|
130
|
+
- lib/sidekiq-resque_status/sidekiq_worker_with_status.rb
|
131
|
+
- lib/sidekiq-resque_status/version.rb
|
132
|
+
- sidekiq-resque_status.gemspec
|
133
|
+
- spec/sidekiq-resque_status/test_middleware.rb
|
134
|
+
- spec/sidekiq-resque_status_spec.rb
|
135
|
+
- spec/spec_helper.rb
|
136
|
+
- spec/support/failing_job.rb
|
137
|
+
- spec/support/sleeping_job.rb
|
138
|
+
homepage: ''
|
139
|
+
licenses:
|
140
|
+
- MIT
|
141
|
+
post_install_message:
|
142
|
+
rdoc_options: []
|
143
|
+
require_paths:
|
144
|
+
- lib
|
145
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
147
|
+
requirements:
|
148
|
+
- - ! '>='
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
152
|
+
none: false
|
153
|
+
requirements:
|
154
|
+
- - ! '>='
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
requirements: []
|
158
|
+
rubyforge_project:
|
159
|
+
rubygems_version: 1.8.23
|
160
|
+
signing_key:
|
161
|
+
specification_version: 3
|
162
|
+
summary: sidekiq-resque_status is an extension to the Sidekiq queue system. It has
|
163
|
+
been created to centralize Resque jobs statuses and Sidekiq workers statuses inside
|
164
|
+
the resque-web interface.
|
165
|
+
test_files:
|
166
|
+
- spec/sidekiq-resque_status/test_middleware.rb
|
167
|
+
- spec/sidekiq-resque_status_spec.rb
|
168
|
+
- spec/spec_helper.rb
|
169
|
+
- spec/support/failing_job.rb
|
170
|
+
- spec/support/sleeping_job.rb
|