sidekiq-worker_stats 0.0.2 → 0.0.3
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/README.md +26 -1
- data/lib/sidekiq/worker_stats.rb +0 -13
- data/lib/sidekiq/worker_stats/configuration.rb +15 -5
- data/lib/sidekiq/worker_stats/middleware.rb +15 -42
- data/lib/sidekiq/worker_stats/stats.rb +86 -0
- data/lib/sidekiq/worker_stats/version.rb +1 -1
- data/lib/sidekiq/worker_stats/views/worker_stats.erb +1 -1
- data/lib/sidekiq/worker_stats/views/worker_stats_single.erb +2 -2
- data/lib/sidekiq/worker_stats/web.rb +6 -3
- data/test/worker_stats/test_middleware.rb +35 -14
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1543112b4d14962857125dc3f4b1f87696fbf30
|
4
|
+
data.tar.gz: e1f94d3c2cde419a3ac7b0b791cdb78a548f5d71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29dd66f6095e0f074fa92e17591bde836e2ab2908c95bf0e173e4ba845c8b83fddf10a3f6fd88f8bda462bd5dc2aaad53a1062193f589728789602d4812b7a99
|
7
|
+
data.tar.gz: a49ec725dac939319000624e8eacd1f1522a36af6437ab2dc67d21c3e39c96ba706a1928c183b4a480451f1c3c975a619c4803f782a1dc0d5a13f0de93520748
|
data/README.md
CHANGED
@@ -1,3 +1,28 @@
|
|
1
1
|
# sidekiq-worker\_stats
|
2
|
+
**Statistics for sidekiq workers**
|
2
3
|
|
3
|
-
|
4
|
+
Build status - TODO
|
5
|
+
|
6
|
+
The following statistics are saved for analysis:
|
7
|
+
|
8
|
+
* Start Time
|
9
|
+
* Stop Time
|
10
|
+
* Runtime
|
11
|
+
* Memory
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add `sidekiq-worker_stats` to your Gemfile
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'sidekiq-worker_stats'
|
19
|
+
```
|
20
|
+
|
21
|
+
and install
|
22
|
+
|
23
|
+
```bash
|
24
|
+
$ bundle install
|
25
|
+
```
|
26
|
+
|
27
|
+
## Configuration
|
28
|
+
We can configure
|
data/lib/sidekiq/worker_stats.rb
CHANGED
@@ -1,24 +1,11 @@
|
|
1
1
|
require 'sidekiq'
|
2
2
|
|
3
|
-
require 'sidekiq/worker_stats/configuration'
|
4
3
|
require 'sidekiq/worker_stats/middleware'
|
5
4
|
require 'sidekiq/worker_stats/web' if defined?(Sidekiq::Web)
|
6
5
|
|
7
6
|
module Sidekiq
|
8
7
|
module WorkerStats
|
9
8
|
REDIS_HASH = 'sidekiq:worker_stats'.freeze
|
10
|
-
|
11
|
-
class << self
|
12
|
-
attr_writer :configuration
|
13
|
-
|
14
|
-
def configuration
|
15
|
-
@configuration ||= Configuration.new
|
16
|
-
end
|
17
|
-
|
18
|
-
def configure
|
19
|
-
yield(configuration)
|
20
|
-
end
|
21
|
-
end
|
22
9
|
end
|
23
10
|
end
|
24
11
|
|
@@ -1,13 +1,23 @@
|
|
1
1
|
module Sidekiq
|
2
2
|
module WorkerStats
|
3
3
|
class Configuration
|
4
|
-
|
5
|
-
|
4
|
+
DEFAULT_MEM_SLEEP = 5.freeze
|
5
|
+
DEFAULT_ENABLED = false.freeze
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
attr_reader :klass
|
8
|
+
|
9
|
+
def initialize(klass)
|
10
|
+
@klass = klass
|
11
|
+
end
|
12
|
+
|
13
|
+
def mem_sleep
|
14
|
+
@klass.get_sidekiq_options['worker_stats_mem_sleep'] || Sidekiq::WorkerStats::Configuration::DEFAULT_MEM_SLEEP
|
15
|
+
end
|
16
|
+
|
17
|
+
def enabled
|
18
|
+
@klass.get_sidekiq_options['worker_stats_enabled'] || Sidekiq::WorkerStats::Configuration::DEFAULT_ENABLED
|
10
19
|
end
|
11
20
|
end
|
12
21
|
end
|
13
22
|
end
|
23
|
+
|
@@ -1,53 +1,26 @@
|
|
1
|
-
require '
|
1
|
+
require 'sidekiq/worker_stats/configuration'
|
2
|
+
require 'sidekiq/worker_stats/stats'
|
2
3
|
|
3
4
|
module Sidekiq
|
4
5
|
module WorkerStats
|
5
6
|
class Middleware
|
6
7
|
def call(worker, msg, queue)
|
7
|
-
|
8
|
-
worker_stats[:start] = Time.now.to_i
|
9
|
-
worker_stats[:status] = 'started'
|
8
|
+
c = Sidekiq::WorkerStats::Configuration.new(worker.class)
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
worker_stats[:page_size] = `getconf PAGESIZE`.to_i
|
15
|
-
worker_stats[:mem] = {}
|
16
|
-
worker_stats[:mem][Time.now.to_i] = `awk '{ print $2 }' /proc/#{worker_stats[:pid]}/statm`.strip.to_i * worker_stats[:page_size]
|
17
|
-
|
18
|
-
thr = Thread.new do
|
19
|
-
while true do
|
20
|
-
sleep Sidekiq::WorkerStats.configuration.time
|
21
|
-
worker_stats[:mem][Time.now.to_i] = `awk '{ print $2 }' /proc/#{worker_stats[:pid]}/statm`.strip.to_i * worker_stats[:page_size]
|
22
|
-
end
|
10
|
+
unless c.enabled
|
11
|
+
yield
|
12
|
+
return
|
23
13
|
end
|
24
14
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
worker_stats[:runtime] = worker_stats[:stop] - worker_stats[:start]
|
35
|
-
|
36
|
-
worker_stats[:queue] = queue
|
37
|
-
worker_stats[:class] = worker.class.to_s
|
38
|
-
|
39
|
-
thr.exit if thr != nil
|
40
|
-
|
41
|
-
worker_key = "#{worker_stats[:class]}:#{worker_stats[:start]}:#{worker_stats[:jid]}"
|
42
|
-
|
43
|
-
save_worker_stats worker_key, worker_stats
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def save_worker_stats(key, worker_stats)
|
49
|
-
Sidekiq.redis do |redis|
|
50
|
-
redis.hset REDIS_HASH, key, JSON.generate(worker_stats)
|
15
|
+
begin
|
16
|
+
s = Sidekiq::WorkerStats::Stats.new(worker, msg, queue, c)
|
17
|
+
yield
|
18
|
+
s.stop('completed')
|
19
|
+
rescue => e
|
20
|
+
s.stop('failed')
|
21
|
+
raise e
|
22
|
+
ensure
|
23
|
+
s.save
|
51
24
|
end
|
52
25
|
end
|
53
26
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Sidekiq
|
5
|
+
module WorkerStats
|
6
|
+
class Stats
|
7
|
+
attr_reader :pid
|
8
|
+
attr_reader :jid
|
9
|
+
attr_reader :queue
|
10
|
+
attr_reader :klass
|
11
|
+
|
12
|
+
attr_reader :start
|
13
|
+
attr_reader :stop
|
14
|
+
attr_reader :walltime
|
15
|
+
attr_reader :status
|
16
|
+
attr_reader :page_size
|
17
|
+
attr_reader :mem
|
18
|
+
|
19
|
+
attr_reader :mem_thr
|
20
|
+
attr_reader :config
|
21
|
+
|
22
|
+
def initialize(worker, msg, queue, config)
|
23
|
+
@config = config
|
24
|
+
@queue = queue
|
25
|
+
@klass = worker.class
|
26
|
+
@pid = Process.pid
|
27
|
+
@jid = worker.jid
|
28
|
+
@page_size = `getconf PAGESIZE`.to_i
|
29
|
+
start
|
30
|
+
end
|
31
|
+
|
32
|
+
def start
|
33
|
+
@status = 'started'
|
34
|
+
@start = Time.now.to_f
|
35
|
+
memory_measurement
|
36
|
+
end
|
37
|
+
|
38
|
+
def stop(status)
|
39
|
+
@stop = Time.now.to_f
|
40
|
+
@walltime = @stop - @start
|
41
|
+
@status = status
|
42
|
+
|
43
|
+
mem_thr.exit if mem_thr != nil
|
44
|
+
@mem[Time.now.to_f] = current_memory
|
45
|
+
end
|
46
|
+
|
47
|
+
def save
|
48
|
+
worker_key = "#{@klass}:#{@start}:#{@jid}"
|
49
|
+
data = {
|
50
|
+
pid: @pid,
|
51
|
+
jid: @jid,
|
52
|
+
queue: @queue,
|
53
|
+
class: @klass,
|
54
|
+
start: @start,
|
55
|
+
stop: @stop,
|
56
|
+
walltime: @walltime,
|
57
|
+
status: @status,
|
58
|
+
page_size: @page_size,
|
59
|
+
mem: @mem
|
60
|
+
}
|
61
|
+
|
62
|
+
Sidekiq.redis do |redis|
|
63
|
+
redis.hset Sidekiq::WorkerStats::REDIS_HASH, worker_key, JSON.generate(data)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def memory_measurement
|
70
|
+
@mem = {}
|
71
|
+
mem_sleep = @config.mem_sleep
|
72
|
+
puts mem_sleep
|
73
|
+
@mem_thr = Thread.new do
|
74
|
+
while true do
|
75
|
+
@mem[Time.now.to_f] = current_memory
|
76
|
+
sleep mem_sleep
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def current_memory
|
82
|
+
`awk '{ print $2 }' /proc/#{@pid}/statm`.strip.to_i * @page_size
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -19,7 +19,7 @@
|
|
19
19
|
<td><a href="<%= root_path %>worker_stats/<%= key.to_s %>"><%= worker["class"].to_s %></a></td>
|
20
20
|
<td><%= Time.at(worker["start"]).strftime "%Y-%m-%d %H:%M:%S" %></td>
|
21
21
|
<td><%= Time.at(worker["stop"]).strftime "%Y-%m-%d %H:%M:%S" %></td>
|
22
|
-
<td><%= "#{worker["
|
22
|
+
<td><%= "#{worker["walltime"]} s" %></td>
|
23
23
|
<td><%= "#{(worker["mem"].values.inject(:+) / worker["mem"].count) / 1024 / 1024} Mb" %></td>
|
24
24
|
<td><%= "#{(worker["mem"].values.max / 1024 / 1024)} Mb" %></td>
|
25
25
|
</tr>
|
@@ -38,7 +38,7 @@
|
|
38
38
|
</tr>
|
39
39
|
<tr>
|
40
40
|
<td>Runtime</td>
|
41
|
-
<td><%= @worker["
|
41
|
+
<td><%= @worker["walltime"] %> seconds</td>
|
42
42
|
</tr>
|
43
43
|
</tbody>
|
44
44
|
</table>
|
@@ -57,7 +57,7 @@
|
|
57
57
|
<tbody>
|
58
58
|
<% @worker["mem"].each do |time, mem| %>
|
59
59
|
<tr>
|
60
|
-
<td><%= (time.
|
60
|
+
<td><%= (time.to_f - @worker["start"]).round(2).to_s %> seconds</td>
|
61
61
|
<td><%= "#{mem / 1024 / 1024} Mb" %></td>
|
62
62
|
</tr>
|
63
63
|
<% end %>
|
@@ -13,7 +13,8 @@ module Sidekiq
|
|
13
13
|
Sidekiq.redis do |redis|
|
14
14
|
keys = redis.hkeys REDIS_HASH
|
15
15
|
keys.each do |key|
|
16
|
-
|
16
|
+
worker_stats = redis.hget(REDIS_HASH, key)
|
17
|
+
@workers[key] = JSON.parse(worker_stats) if worker_stats != nil
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
@@ -34,5 +35,7 @@ module Sidekiq
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
|
-
|
38
|
-
Sidekiq::Web.
|
38
|
+
if defined?(Sidekiq::Web)
|
39
|
+
Sidekiq::Web.register Sidekiq::WorkerStats::Web
|
40
|
+
Sidekiq::Web.tabs['Worker Stats'] = 'worker_stats'
|
41
|
+
end
|
@@ -6,55 +6,76 @@ require 'sidekiq'
|
|
6
6
|
require 'sidekiq/testing'
|
7
7
|
require 'sidekiq/worker_stats'
|
8
8
|
|
9
|
-
|
10
|
-
class WorkerHelper
|
9
|
+
class BasicWorker
|
11
10
|
include Sidekiq::Worker
|
12
11
|
|
12
|
+
sidekiq_options({
|
13
|
+
worker_stats_enabled: true,
|
14
|
+
worker_stats_mem_sleep: 1
|
15
|
+
})
|
16
|
+
|
13
17
|
def perform
|
14
18
|
# Let's use some memory
|
15
19
|
a = []
|
16
|
-
for i in 1..
|
20
|
+
for i in 1..5000000
|
17
21
|
a << i.to_s * 10
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
22
|
-
class
|
26
|
+
class NoStatsWorker
|
23
27
|
include Sidekiq::Worker
|
24
28
|
|
29
|
+
sidekiq_options({
|
30
|
+
worker_stats_enabled: false
|
31
|
+
})
|
32
|
+
|
25
33
|
def perform
|
26
|
-
raise StandardError.new("Error")
|
27
34
|
end
|
28
35
|
end
|
29
36
|
|
30
|
-
class
|
31
|
-
include
|
37
|
+
class ErrorWorker
|
38
|
+
include Sidekiq::Worker
|
39
|
+
|
40
|
+
sidekiq_options({
|
41
|
+
worker_stats_enabled: true,
|
42
|
+
worker_stats_mem_sleep: 1
|
43
|
+
})
|
32
44
|
|
33
|
-
def
|
34
|
-
|
45
|
+
def perform
|
46
|
+
raise StandardError.new("Error")
|
35
47
|
end
|
48
|
+
end
|
36
49
|
|
50
|
+
class TestMiddleware < Minitest::Test
|
37
51
|
def setup
|
38
52
|
Sidekiq::Testing.server_middleware do |chain|
|
39
53
|
chain.add Sidekiq::WorkerStats::Middleware
|
40
54
|
end
|
41
55
|
end
|
42
56
|
|
43
|
-
def
|
57
|
+
def test_basic_worker_stats_are_saved
|
44
58
|
Sidekiq::Testing.inline! do
|
45
|
-
|
59
|
+
BasicWorker.perform_async
|
46
60
|
end
|
47
61
|
end
|
48
62
|
|
49
|
-
def
|
50
|
-
|
63
|
+
def test_no_stats_worker
|
64
|
+
Sidekiq::Testing.inline! do
|
65
|
+
NoStatsWorker.perform_async
|
66
|
+
end
|
51
67
|
end
|
52
68
|
|
53
69
|
def test_that_middleware_raises_error
|
54
70
|
Sidekiq::Testing.inline! do
|
55
71
|
assert_raises StandardError do
|
56
|
-
|
72
|
+
ErrorWorker.perform_async
|
57
73
|
end
|
58
74
|
end
|
59
75
|
end
|
76
|
+
|
77
|
+
def test_that_middleware_reports_end
|
78
|
+
skip 'todo'
|
79
|
+
end
|
80
|
+
|
60
81
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-worker_stats
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexandre Jesus
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sidekiq
|
@@ -99,6 +99,7 @@ files:
|
|
99
99
|
- lib/sidekiq/worker_stats.rb
|
100
100
|
- lib/sidekiq/worker_stats/configuration.rb
|
101
101
|
- lib/sidekiq/worker_stats/middleware.rb
|
102
|
+
- lib/sidekiq/worker_stats/stats.rb
|
102
103
|
- lib/sidekiq/worker_stats/version.rb
|
103
104
|
- lib/sidekiq/worker_stats/views/worker_stats.erb
|
104
105
|
- lib/sidekiq/worker_stats/views/worker_stats_single.erb
|