sidekiq 5.2.7 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sidekiq might be problematic. Click here for more details.

Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -2
  3. data/.standard.yml +20 -0
  4. data/6.0-Upgrade.md +70 -0
  5. data/Changes.md +34 -0
  6. data/Ent-2.0-Upgrade.md +37 -0
  7. data/Ent-Changes.md +12 -0
  8. data/Gemfile +12 -11
  9. data/Gemfile.lock +196 -0
  10. data/Pro-5.0-Upgrade.md +25 -0
  11. data/Pro-Changes.md +12 -3
  12. data/README.md +16 -30
  13. data/Rakefile +5 -4
  14. data/bin/sidekiqload +26 -22
  15. data/bin/sidekiqmon +9 -0
  16. data/lib/generators/sidekiq/templates/worker_test.rb.erb +1 -1
  17. data/lib/generators/sidekiq/worker_generator.rb +12 -14
  18. data/lib/sidekiq.rb +53 -42
  19. data/lib/sidekiq/api.rb +138 -151
  20. data/lib/sidekiq/cli.rb +97 -162
  21. data/lib/sidekiq/client.rb +45 -46
  22. data/lib/sidekiq/delay.rb +5 -6
  23. data/lib/sidekiq/exception_handler.rb +10 -12
  24. data/lib/sidekiq/extensions/action_mailer.rb +10 -20
  25. data/lib/sidekiq/extensions/active_record.rb +9 -7
  26. data/lib/sidekiq/extensions/class_methods.rb +9 -7
  27. data/lib/sidekiq/extensions/generic_proxy.rb +4 -4
  28. data/lib/sidekiq/fetch.rb +5 -6
  29. data/lib/sidekiq/job_logger.rb +37 -7
  30. data/lib/sidekiq/job_retry.rb +45 -58
  31. data/lib/sidekiq/launcher.rb +59 -51
  32. data/lib/sidekiq/logger.rb +69 -0
  33. data/lib/sidekiq/manager.rb +7 -9
  34. data/lib/sidekiq/middleware/chain.rb +3 -2
  35. data/lib/sidekiq/middleware/i18n.rb +5 -7
  36. data/lib/sidekiq/monitor.rb +148 -0
  37. data/lib/sidekiq/paginator.rb +11 -12
  38. data/lib/sidekiq/processor.rb +52 -49
  39. data/lib/sidekiq/rails.rb +23 -29
  40. data/lib/sidekiq/redis_connection.rb +31 -37
  41. data/lib/sidekiq/scheduled.rb +17 -19
  42. data/lib/sidekiq/testing.rb +22 -23
  43. data/lib/sidekiq/testing/inline.rb +2 -1
  44. data/lib/sidekiq/util.rb +17 -14
  45. data/lib/sidekiq/version.rb +2 -1
  46. data/lib/sidekiq/web.rb +41 -49
  47. data/lib/sidekiq/web/action.rb +14 -10
  48. data/lib/sidekiq/web/application.rb +60 -57
  49. data/lib/sidekiq/web/helpers.rb +66 -67
  50. data/lib/sidekiq/web/router.rb +17 -14
  51. data/lib/sidekiq/worker.rb +124 -97
  52. data/sidekiq.gemspec +16 -16
  53. data/web/assets/javascripts/dashboard.js +2 -21
  54. data/web/locales/ja.yml +2 -1
  55. metadata +19 -29
  56. data/.travis.yml +0 -11
  57. data/bin/sidekiqctl +0 -20
  58. data/lib/sidekiq/core_ext.rb +0 -1
  59. data/lib/sidekiq/ctl.rb +0 -221
  60. data/lib/sidekiq/logging.rb +0 -122
  61. data/lib/sidekiq/middleware/server/active_record.rb +0 -23
@@ -1,18 +1,19 @@
1
1
  # frozen_string_literal: true
2
- require 'rack'
2
+
3
+ require "rack"
3
4
 
4
5
  module Sidekiq
5
6
  module WebRouter
6
- GET = 'GET'
7
- DELETE = 'DELETE'
8
- POST = 'POST'
9
- PUT = 'PUT'
10
- PATCH = 'PATCH'
11
- HEAD = 'HEAD'
7
+ GET = "GET"
8
+ DELETE = "DELETE"
9
+ POST = "POST"
10
+ PUT = "PUT"
11
+ PATCH = "PATCH"
12
+ HEAD = "HEAD"
12
13
 
13
- ROUTE_PARAMS = 'rack.route_params'
14
- REQUEST_METHOD = 'REQUEST_METHOD'
15
- PATH_INFO = 'PATH_INFO'
14
+ ROUTE_PARAMS = "rack.route_params"
15
+ REQUEST_METHOD = "REQUEST_METHOD"
16
+ PATH_INFO = "PATH_INFO"
16
17
 
17
18
  def get(path, &block)
18
19
  route(GET, path, &block)
@@ -35,7 +36,7 @@ module Sidekiq
35
36
  end
36
37
 
37
38
  def route(method, path, &block)
38
- @routes ||= { GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => [] }
39
+ @routes ||= {GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => []}
39
40
 
40
41
  @routes[method] << WebRoute.new(method, path, block)
41
42
  @routes[HEAD] << WebRoute.new(method, path, block) if method == GET
@@ -50,7 +51,8 @@ module Sidekiq
50
51
  path_info = "/" if path_info == ""
51
52
 
52
53
  @routes[request_method].each do |route|
53
- if params = route.match(request_method, path_info)
54
+ params = route.match(request_method, path_info)
55
+ if params
54
56
  env[ROUTE_PARAMS] = params
55
57
 
56
58
  return WebAction.new(env, route.block)
@@ -77,7 +79,7 @@ module Sidekiq
77
79
  end
78
80
 
79
81
  def compile
80
- if pattern.match(NAMED_SEGMENTS_PATTERN)
82
+ if pattern.match?(NAMED_SEGMENTS_PATTERN)
81
83
  p = pattern.gsub(NAMED_SEGMENTS_PATTERN, '/\1(?<\2>[^$/]+)')
82
84
 
83
85
  Regexp.new("\\A#{p}\\Z")
@@ -91,7 +93,8 @@ module Sidekiq
91
93
  when String
92
94
  {} if path == matcher
93
95
  else
94
- if path_match = path.match(matcher)
96
+ path_match = path.match(matcher)
97
+ if path_match
95
98
  Hash[path_match.names.map(&:to_sym).zip(path_match.captures)]
96
99
  end
97
100
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
- require 'sidekiq/client'
3
2
 
4
- module Sidekiq
3
+ require "sidekiq/client"
5
4
 
5
+ module Sidekiq
6
6
  ##
7
7
  # Include this module in your worker class and you can easily create
8
8
  # asynchronous jobs:
@@ -21,15 +21,124 @@ module Sidekiq
21
21
  #
22
22
  # Note that perform_async is a class method, perform is an instance method.
23
23
  module Worker
24
+ ##
25
+ # The Options module is extracted so we can include it in ActiveJob::Base
26
+ # and allow native AJs to configure Sidekiq features/internals.
27
+ module Options
28
+ def self.included(base)
29
+ base.extend(ClassMethods)
30
+ base.sidekiq_class_attribute :sidekiq_options_hash
31
+ base.sidekiq_class_attribute :sidekiq_retry_in_block
32
+ base.sidekiq_class_attribute :sidekiq_retries_exhausted_block
33
+ end
34
+
35
+ module ClassMethods
36
+ ACCESSOR_MUTEX = Mutex.new
37
+
38
+ ##
39
+ # Allows customization for this type of Worker.
40
+ # Legal options:
41
+ #
42
+ # queue - name of queue to use for this job type, default *default*
43
+ # retry - enable retries for this Worker in case of error during execution,
44
+ # *true* to use the default or *Integer* count
45
+ # backtrace - whether to save any error backtrace in the retry payload to display in web UI,
46
+ # can be true, false or an integer number of lines to save, default *false*
47
+ #
48
+ # In practice, any option is allowed. This is the main mechanism to configure the
49
+ # options for a specific job.
50
+ def sidekiq_options(opts = {})
51
+ opts = Hash[opts.map { |k, v| [k.to_s, v] }] # stringify
52
+ self.sidekiq_options_hash = get_sidekiq_options.merge(Hash[opts.map { |k, v| [k.to_s, v] }])
53
+ end
54
+
55
+ def sidekiq_retry_in(&block)
56
+ self.sidekiq_retry_in_block = block
57
+ end
58
+
59
+ def sidekiq_retries_exhausted(&block)
60
+ self.sidekiq_retries_exhausted_block = block
61
+ end
62
+
63
+ def get_sidekiq_options # :nodoc:
64
+ self.sidekiq_options_hash ||= Sidekiq.default_worker_options
65
+ end
66
+
67
+ def sidekiq_class_attribute(*attrs)
68
+ instance_reader = true
69
+ instance_writer = true
70
+
71
+ attrs.each do |name|
72
+ synchronized_getter = "__synchronized_#{name}"
73
+
74
+ singleton_class.instance_eval do
75
+ undef_method(name) if method_defined?(name) || private_method_defined?(name)
76
+ end
77
+
78
+ define_singleton_method(synchronized_getter) { nil }
79
+ singleton_class.class_eval do
80
+ private(synchronized_getter)
81
+ end
82
+
83
+ define_singleton_method(name) { ACCESSOR_MUTEX.synchronize { send synchronized_getter } }
84
+
85
+ ivar = "@#{name}"
86
+
87
+ singleton_class.instance_eval do
88
+ m = "#{name}="
89
+ undef_method(m) if method_defined?(m) || private_method_defined?(m)
90
+ end
91
+ define_singleton_method("#{name}=") do |val|
92
+ singleton_class.class_eval do
93
+ ACCESSOR_MUTEX.synchronize do
94
+ undef_method(synchronized_getter) if method_defined?(synchronized_getter) || private_method_defined?(synchronized_getter)
95
+ define_method(synchronized_getter) { val }
96
+ end
97
+ end
98
+
99
+ if singleton_class?
100
+ class_eval do
101
+ undef_method(name) if method_defined?(name) || private_method_defined?(name)
102
+ define_method(name) do
103
+ if instance_variable_defined? ivar
104
+ instance_variable_get ivar
105
+ else
106
+ singleton_class.send name
107
+ end
108
+ end
109
+ end
110
+ end
111
+ val
112
+ end
113
+
114
+ if instance_reader
115
+ undef_method(name) if method_defined?(name) || private_method_defined?(name)
116
+ define_method(name) do
117
+ if instance_variable_defined?(ivar)
118
+ instance_variable_get ivar
119
+ else
120
+ self.class.public_send name
121
+ end
122
+ end
123
+ end
124
+
125
+ if instance_writer
126
+ m = "#{name}="
127
+ undef_method(m) if method_defined?(m) || private_method_defined?(m)
128
+ attr_writer name
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+
24
135
  attr_accessor :jid
25
136
 
26
137
  def self.included(base)
27
- raise ArgumentError, "You cannot include Sidekiq::Worker in an ActiveJob: #{base.name}" if base.ancestors.any? {|c| c.name == 'ActiveJob::Base' }
138
+ raise ArgumentError, "Sidekiq::Worker cannot be included in an ActiveJob: #{base.name}" if base.ancestors.any? { |c| c.name == "ActiveJob::Base" }
28
139
 
140
+ base.include(Options)
29
141
  base.extend(ClassMethods)
30
- base.sidekiq_class_attribute :sidekiq_options_hash
31
- base.sidekiq_class_attribute :sidekiq_retry_in_block
32
- base.sidekiq_class_attribute :sidekiq_retries_exhausted_block
33
142
  end
34
143
 
35
144
  def logger
@@ -52,7 +161,7 @@ module Sidekiq
52
161
  end
53
162
 
54
163
  def perform_async(*args)
55
- @klass.client_push(@opts.merge('args' => args, 'class' => @klass))
164
+ @klass.client_push(@opts.merge("args" => args, "class" => @klass))
56
165
  end
57
166
 
58
167
  # +interval+ must be a timestamp, numeric or something that acts
@@ -62,17 +171,15 @@ module Sidekiq
62
171
  now = Time.now.to_f
63
172
  ts = (int < 1_000_000_000 ? now + int : int)
64
173
 
65
- payload = @opts.merge('class' => @klass, 'args' => args, 'at' => ts)
174
+ payload = @opts.merge("class" => @klass, "args" => args, "at" => ts)
66
175
  # Optimization to enqueue something now that is scheduled to go out now or in the past
67
- payload.delete('at') if ts <= now
176
+ payload.delete("at") if ts <= now
68
177
  @klass.client_push(payload)
69
178
  end
70
179
  alias_method :perform_at, :perform_in
71
180
  end
72
181
 
73
182
  module ClassMethods
74
- ACCESSOR_MUTEX = Mutex.new
75
-
76
183
  def delay(*args)
77
184
  raise ArgumentError, "Do not call .delay on a Sidekiq::Worker class, call .perform_async"
78
185
  end
@@ -90,7 +197,7 @@ module Sidekiq
90
197
  end
91
198
 
92
199
  def perform_async(*args)
93
- client_push('class' => self, 'args' => args)
200
+ client_push("class" => self, "args" => args)
94
201
  end
95
202
 
96
203
  # +interval+ must be a timestamp, numeric or something that acts
@@ -100,10 +207,10 @@ module Sidekiq
100
207
  now = Time.now.to_f
101
208
  ts = (int < 1_000_000_000 ? now + int : int)
102
209
 
103
- item = { 'class' => self, 'args' => args, 'at' => ts }
210
+ item = {"class" => self, "args" => args, "at" => ts}
104
211
 
105
212
  # Optimization to enqueue something now that is scheduled to go out now or in the past
106
- item.delete('at') if ts <= now
213
+ item.delete("at") if ts <= now
107
214
 
108
215
  client_push(item)
109
216
  end
@@ -122,25 +229,12 @@ module Sidekiq
122
229
  #
123
230
  # In practice, any option is allowed. This is the main mechanism to configure the
124
231
  # options for a specific job.
125
- def sidekiq_options(opts={})
126
- # stringify
127
- self.sidekiq_options_hash = get_sidekiq_options.merge(Hash[opts.map{|k, v| [k.to_s, v]}])
128
- end
129
-
130
- def sidekiq_retry_in(&block)
131
- self.sidekiq_retry_in_block = block
132
- end
133
-
134
- def sidekiq_retries_exhausted(&block)
135
- self.sidekiq_retries_exhausted_block = block
136
- end
137
-
138
- def get_sidekiq_options # :nodoc:
139
- self.sidekiq_options_hash ||= Sidekiq.default_worker_options
232
+ def sidekiq_options(opts = {})
233
+ super
140
234
  end
141
235
 
142
236
  def client_push(item) # :nodoc:
143
- pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options['pool'] || Sidekiq.redis_pool
237
+ pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options["pool"] || Sidekiq.redis_pool
144
238
  # stringify
145
239
  item.keys.each do |key|
146
240
  item[key.to_s] = item.delete(key)
@@ -148,73 +242,6 @@ module Sidekiq
148
242
 
149
243
  Sidekiq::Client.new(pool).push(item)
150
244
  end
151
-
152
- def sidekiq_class_attribute(*attrs)
153
- instance_reader = true
154
- instance_writer = true
155
-
156
- attrs.each do |name|
157
- synchronized_getter = "__synchronized_#{name}"
158
-
159
- singleton_class.instance_eval do
160
- undef_method(name) if method_defined?(name) || private_method_defined?(name)
161
- end
162
-
163
- define_singleton_method(synchronized_getter) { nil }
164
- singleton_class.class_eval do
165
- private(synchronized_getter)
166
- end
167
-
168
- define_singleton_method(name) { ACCESSOR_MUTEX.synchronize { send synchronized_getter } }
169
-
170
- ivar = "@#{name}"
171
-
172
- singleton_class.instance_eval do
173
- m = "#{name}="
174
- undef_method(m) if method_defined?(m) || private_method_defined?(m)
175
- end
176
- define_singleton_method("#{name}=") do |val|
177
- singleton_class.class_eval do
178
- ACCESSOR_MUTEX.synchronize do
179
- undef_method(synchronized_getter) if method_defined?(synchronized_getter) || private_method_defined?(synchronized_getter)
180
- define_method(synchronized_getter) { val }
181
- end
182
- end
183
-
184
- if singleton_class?
185
- class_eval do
186
- undef_method(name) if method_defined?(name) || private_method_defined?(name)
187
- define_method(name) do
188
- if instance_variable_defined? ivar
189
- instance_variable_get ivar
190
- else
191
- singleton_class.send name
192
- end
193
- end
194
- end
195
- end
196
- val
197
- end
198
-
199
- if instance_reader
200
- undef_method(name) if method_defined?(name) || private_method_defined?(name)
201
- define_method(name) do
202
- if instance_variable_defined?(ivar)
203
- instance_variable_get ivar
204
- else
205
- self.class.public_send name
206
- end
207
- end
208
- end
209
-
210
- if instance_writer
211
- m = "#{name}="
212
- undef_method(m) if method_defined?(m) || private_method_defined?(m)
213
- attr_writer name
214
- end
215
- end
216
- end
217
-
218
245
  end
219
246
  end
220
247
  end
@@ -1,21 +1,21 @@
1
- require_relative 'lib/sidekiq/version'
1
+ require_relative "lib/sidekiq/version"
2
2
 
3
3
  Gem::Specification.new do |gem|
4
- gem.authors = ["Mike Perham"]
5
- gem.email = ["mperham@gmail.com"]
6
- gem.summary = "Simple, efficient background processing for Ruby"
7
- gem.description = "Simple, efficient background processing for Ruby."
8
- gem.homepage = "http://sidekiq.org"
9
- gem.license = "LGPL-3.0"
4
+ gem.authors = ["Mike Perham"]
5
+ gem.email = ["mperham@gmail.com"]
6
+ gem.summary = "Simple, efficient background processing for Ruby"
7
+ gem.description = "Simple, efficient background processing for Ruby."
8
+ gem.homepage = "http://sidekiq.org"
9
+ gem.license = "LGPL-3.0"
10
10
 
11
- gem.executables = ['sidekiq', 'sidekiqctl']
12
- gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n")
13
- gem.name = "sidekiq"
14
- gem.version = Sidekiq::VERSION
15
- gem.required_ruby_version = ">= 2.2.2"
11
+ gem.executables = ["sidekiq"]
12
+ gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n")
13
+ gem.name = "sidekiq"
14
+ gem.version = Sidekiq::VERSION
15
+ gem.required_ruby_version = ">= 2.5.0"
16
16
 
17
- gem.add_dependency 'redis', '>= 3.3.5', '< 5'
18
- gem.add_dependency 'connection_pool', '~> 2.2', '>= 2.2.2'
19
- gem.add_dependency 'rack', '>= 1.5.0'
20
- gem.add_dependency 'rack-protection', '>= 1.5.0'
17
+ gem.add_dependency "redis", ">= 4.1.0"
18
+ gem.add_dependency "connection_pool", ">= 2.2.2"
19
+ gem.add_dependency "rack", ">= 2.0.0"
20
+ gem.add_dependency "rack-protection", ">= 2.0.0"
21
21
  end
@@ -16,10 +16,8 @@ var gridSize=(this.orientation=="right"?1:-1)*this.graph.width;this.graph.vis.ap
16
16
  var nodes=vis.selectAll("path").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:rect").attr("x",function(d){return graph.x(d.x)+barXOffset}).attr("y",function(d){return graph.y(d.y0+Math.abs(d.y))*(d.y<0?-1:1)}).attr("width",seriesBarWidth).attr("height",function(d){return graph.y.magnitude(Math.abs(d.y))}).attr("opacity",series.opacity).attr("transform",transform);Array.prototype.forEach.call(nodes[0],function(n){n.setAttribute("fill",series.color)});if(this.unstack)barXOffset+=seriesBarWidth},this)},_frequentInterval:function(data){var intervalCounts={};for(var i=0;i<data.length-1;i++){var interval=data[i+1].x-data[i].x;intervalCounts[interval]=intervalCounts[interval]||0;intervalCounts[interval]++}var frequentInterval={count:0,magnitude:1};var keysSorted=Rickshaw.keys(intervalCounts).sort(function asc(a,b){return Number(a)-Number(b)});keysSorted.forEach(function(i){if(frequentInterval.count<intervalCounts[i]){frequentInterval={count:intervalCounts[i],magnitude:i}}});return frequentInterval}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Area");Rickshaw.Graph.Renderer.Area=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"area",defaults:function($super){return Rickshaw.extend($super(),{unstack:false,fill:false,stroke:false})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.area().x(function(d){return graph.x(d.x)}).y0(function(d){return graph.y(d.y0)}).y1(function(d){return graph.y(d.y+d.y0)}).interpolate(graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory},seriesStrokeFactory:function(){var graph=this.graph;var factory=d3.svg.line().x(function(d){return graph.x(d.x)}).y(function(d){return graph.y(d.y+d.y0)}).interpolate(graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var method=this.unstack?"append":"insert";var data=series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});var nodes=vis.selectAll("path").data(data).enter()[method]("svg:g","g");nodes.append("svg:path").attr("d",this.seriesPathFactory()).attr("class","area");if(this.stroke){nodes.append("svg:path").attr("d",this.seriesStrokeFactory()).attr("class","line")}var i=0;series.forEach(function(series){if(series.disabled)return;series.path=nodes[0][i++];this._styleSeries(series)},this)},_styleSeries:function(series){if(!series.path)return;d3.select(series.path).select(".area").attr("fill",series.color);if(this.stroke){d3.select(series.path).select(".line").attr("fill","none").attr("stroke",series.stroke||d3.interpolateRgb(series.color,"black")(.125)).attr("stroke-width",this.strokeWidth)}if(series.className){series.path.setAttribute("class",series.className)}}});Rickshaw.namespace("Rickshaw.Graph.Renderer.ScatterPlot");Rickshaw.Graph.Renderer.ScatterPlot=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"scatterplot",defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:true,stroke:false,padding:{top:.01,right:.01,bottom:.01,left:.01},dotSize:4})},initialize:function($super,args){$super(args)},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;var dotSize=this.dotSize;vis.selectAll("*").remove();series.forEach(function(series){if(series.disabled)return;var opacity=series.opacity?series.opacity:1;var nodes=vis.selectAll("path").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:circle").attr("cx",function(d){return graph.x(d.x)}).attr("cy",function(d){return graph.y(d.y)}).attr("r",function(d){return"r"in d?d.r:dotSize}).attr("opacity",function(d){return"opacity"in d?d.opacity:opacity});if(series.className){nodes.classed(series.className,true)}Array.prototype.forEach.call(nodes[0],function(n){n.setAttribute("fill",series.color)})},this)}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Multi");Rickshaw.Graph.Renderer.Multi=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"multi",initialize:function($super,args){$super(args)},defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:false,stroke:true})},configure:function($super,args){args=args||{};this.config=args;$super(args)},domain:function($super){this.graph.stackData();var domains=[];var groups=this._groups();this._stack(groups);groups.forEach(function(group){var data=group.series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});if(!data.length)return;var domain=null;if(group.renderer&&group.renderer.domain){domain=group.renderer.domain(data)}else{domain=$super(data)}domains.push(domain)});var xMin=d3.min(domains.map(function(d){return d.x[0]}));var xMax=d3.max(domains.map(function(d){return d.x[1]}));var yMin=d3.min(domains.map(function(d){return d.y[0]}));var yMax=d3.max(domains.map(function(d){return d.y[1]}));return{x:[xMin,xMax],y:[yMin,yMax]}},_groups:function(){var graph=this.graph;var renderGroups={};graph.series.forEach(function(series){if(series.disabled)return;if(!renderGroups[series.renderer]){var ns="http://www.w3.org/2000/svg";var vis=document.createElementNS(ns,"g");graph.vis[0][0].appendChild(vis);var renderer=graph._renderers[series.renderer];var config={};var defaults=[this.defaults(),renderer.defaults(),this.config,this.graph];defaults.forEach(function(d){Rickshaw.extend(config,d)});renderer.configure(config);renderGroups[series.renderer]={renderer:renderer,series:[],vis:d3.select(vis)}}renderGroups[series.renderer].series.push(series)},this);var groups=[];Object.keys(renderGroups).forEach(function(key){var group=renderGroups[key];groups.push(group)});return groups},_stack:function(groups){groups.forEach(function(group){var series=group.series.filter(function(series){return!series.disabled});var data=series.map(function(series){return series.stack});if(!group.renderer.unstack){var layout=d3.layout.stack();var stackedData=Rickshaw.clone(layout(data));series.forEach(function(series,index){series._stack=Rickshaw.clone(stackedData[index])})}},this);return groups},render:function(){this.graph.series.forEach(function(series){if(!series.renderer){throw new Error("Each series needs a renderer for graph 'multi' renderer")}});this.graph.vis.selectAll("*").remove();var groups=this._groups();groups=this._stack(groups);groups.forEach(function(group){var series=group.series.filter(function(series){return!series.disabled});series.active=function(){return series};group.renderer.render({series:series,vis:group.vis});series.forEach(function(s){s.stack=s._stack||s.stack||s.data})})}});Rickshaw.namespace("Rickshaw.Graph.Renderer.LinePlot");Rickshaw.Graph.Renderer.LinePlot=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"lineplot",defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:false,stroke:true,padding:{top:.01,right:.01,bottom:.01,left:.01},dotSize:3,strokeWidth:2})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.line().x(function(d){return graph.x(d.x)}).y(function(d){return graph.y(d.y)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;var dotSize=this.dotSize;vis.selectAll("*").remove();var data=series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});var nodes=vis.selectAll("path").data(data).enter().append("svg:path").attr("d",this.seriesPathFactory());var i=0;series.forEach(function(series){if(series.disabled)return;series.path=nodes[0][i++];this._styleSeries(series)},this);series.forEach(function(series){if(series.disabled)return;var nodes=vis.selectAll("x").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:circle").attr("cx",function(d){return graph.x(d.x)}).attr("cy",function(d){return graph.y(d.y)}).attr("r",function(d){return"r"in d?d.r:dotSize});Array.prototype.forEach.call(nodes[0],function(n){if(!n)return;n.setAttribute("data-color",series.color);n.setAttribute("fill","white");n.setAttribute("stroke",series.color);n.setAttribute("stroke-width",this.strokeWidth)}.bind(this))},this)}});Rickshaw.namespace("Rickshaw.Graph.Smoother");Rickshaw.Graph.Smoother=Rickshaw.Class.create({initialize:function(args){this.graph=args.graph;this.element=args.element;this.aggregationScale=1;this.build();this.graph.stackData.hooks.data.push({name:"smoother",orderPosition:50,f:this.transformer.bind(this)})},build:function(){var self=this;var $=jQuery;if(this.element){$(function(){$(self.element).slider({min:1,max:100,slide:function(event,ui){self.setScale(ui.value)}})})}},setScale:function(scale){if(scale<1){throw"scale out of range: "+scale}this.aggregationScale=scale;this.graph.update()},transformer:function(data){if(this.aggregationScale==1)return data;var aggregatedData=[];data.forEach(function(seriesData){var aggregatedSeriesData=[];while(seriesData.length){var avgX=0,avgY=0;var slice=seriesData.splice(0,this.aggregationScale);slice.forEach(function(d){avgX+=d.x/slice.length;avgY+=d.y/slice.length});aggregatedSeriesData.push({x:avgX,y:avgY})}aggregatedData.push(aggregatedSeriesData)}.bind(this));return aggregatedData}});Rickshaw.namespace("Rickshaw.Graph.Socketio");Rickshaw.Graph.Socketio=Rickshaw.Class.create(Rickshaw.Graph.Ajax,{request:function(){var socket=io.connect(this.dataURL);var self=this;socket.on("rickshaw",function(data){self.success(data)})}});Rickshaw.namespace("Rickshaw.Series");Rickshaw.Series=Rickshaw.Class.create(Array,{initialize:function(data,palette,options){options=options||{};this.palette=new Rickshaw.Color.Palette(palette);this.timeBase=typeof options.timeBase==="undefined"?Math.floor((new Date).getTime()/1e3):options.timeBase;var timeInterval=typeof options.timeInterval=="undefined"?1e3:options.timeInterval;this.setTimeInterval(timeInterval);if(data&&typeof data=="object"&&Array.isArray(data)){data.forEach(function(item){this.addItem(item)},this)}},addItem:function(item){if(typeof item.name==="undefined"){throw"addItem() needs a name"}item.color=item.color||this.palette.color(item.name);item.data=item.data||[];if(item.data.length===0&&this.length&&this.getIndex()>0){this[0].data.forEach(function(plot){item.data.push({x:plot.x,y:0})})}else if(item.data.length===0){item.data.push({x:this.timeBase-(this.timeInterval||0),y:0})}this.push(item);if(this.legend){this.legend.addLine(this.itemByName(item.name))}},addData:function(data,x){var index=this.getIndex();Rickshaw.keys(data).forEach(function(name){if(!this.itemByName(name)){this.addItem({name:name})}},this);this.forEach(function(item){item.data.push({x:x||(index*this.timeInterval||1)+this.timeBase,y:data[item.name]||0})},this)},getIndex:function(){return this[0]&&this[0].data&&this[0].data.length?this[0].data.length:0},itemByName:function(name){for(var i=0;i<this.length;i++){if(this[i].name==name)return this[i]}},setTimeInterval:function(iv){this.timeInterval=iv/1e3},setTimeBase:function(t){this.timeBase=t},dump:function(){var data={timeBase:this.timeBase,timeInterval:this.timeInterval,items:[]};this.forEach(function(item){var newItem={color:item.color,name:item.name,data:[]};item.data.forEach(function(plot){newItem.data.push({x:plot.x,y:plot.y})});data.items.push(newItem)});return data},load:function(data){if(data.timeInterval){this.timeInterval=data.timeInterval}if(data.timeBase){this.timeBase=data.timeBase}if(data.items){data.items.forEach(function(item){this.push(item);if(this.legend){this.legend.addLine(this.itemByName(item.name))}},this)}}});Rickshaw.Series.zeroFill=function(series){Rickshaw.Series.fill(series,0)};Rickshaw.Series.fill=function(series,fill){var x;var i=0;var data=series.map(function(s){return s.data});while(i<Math.max.apply(null,data.map(function(d){return d.length}))){x=Math.min.apply(null,data.filter(function(d){return d[i]}).map(function(d){return d[i].x}));data.forEach(function(d){if(!d[i]||d[i].x!=x){d.splice(i,0,{x:x,y:fill})}});i++}};Rickshaw.namespace("Rickshaw.Series.FixedDuration");Rickshaw.Series.FixedDuration=Rickshaw.Class.create(Rickshaw.Series,{initialize:function(data,palette,options){options=options||{};if(typeof options.timeInterval==="undefined"){throw new Error("FixedDuration series requires timeInterval")}if(typeof options.maxDataPoints==="undefined"){throw new Error("FixedDuration series requires maxDataPoints")}this.palette=new Rickshaw.Color.Palette(palette);this.timeBase=typeof options.timeBase==="undefined"?Math.floor((new Date).getTime()/1e3):options.timeBase;this.setTimeInterval(options.timeInterval);if(this[0]&&this[0].data&&this[0].data.length){this.currentSize=this[0].data.length;this.currentIndex=this[0].data.length}else{this.currentSize=0;this.currentIndex=0}this.maxDataPoints=options.maxDataPoints;if(data&&typeof data=="object"&&Array.isArray(data)){data.forEach(function(item){this.addItem(item)},this);this.currentSize+=1;this.currentIndex+=1}this.timeBase-=(this.maxDataPoints-this.currentSize)*this.timeInterval;if(typeof this.maxDataPoints!=="undefined"&&this.currentSize<this.maxDataPoints){for(var i=this.maxDataPoints-this.currentSize-1;i>1;i--){this.currentSize+=1;this.currentIndex+=1;this.forEach(function(item){item.data.unshift({x:((i-1)*this.timeInterval||1)+this.timeBase,y:0,i:i})},this)}}},addData:function($super,data,x){$super(data,x);this.currentSize+=1;this.currentIndex+=1;if(this.maxDataPoints!==undefined){while(this.currentSize>this.maxDataPoints){this.dropData()}}},dropData:function(){this.forEach(function(item){item.data.splice(0,1)});this.currentSize-=1},getIndex:function(){return this.currentIndex}});return Rickshaw});
17
17
 
18
18
  var poller;
19
-
20
19
  var realtimeGraph = function(updatePath) {
21
20
  var timeInterval = parseInt(localStorage.timeInterval || '5000');
22
-
23
21
  var graphElement = document.getElementById("realtime");
24
22
 
25
23
  var graph = new Rickshaw.Graph( {
@@ -30,8 +28,8 @@ var realtimeGraph = function(updatePath) {
30
28
  interpolation: 'linear',
31
29
 
32
30
  series: new Rickshaw.Series.FixedDuration([{ name: graphElement.dataset.failedLabel, color: '#B1003E' }, { name: graphElement.dataset.processedLabel, color: '#006f68' }], undefined, {
33
- timeInterval: timeInterval,
34
- maxDataPoints: 100,
31
+ timeInterval: timeInterval,
32
+ maxDataPoints: 100,
35
33
  })
36
34
  });
37
35
 
@@ -46,7 +44,6 @@ var realtimeGraph = function(updatePath) {
46
44
  var legend = document.querySelector('#realtime-legend');
47
45
  var Hover = Rickshaw.Class.create(Rickshaw.Graph.HoverDetail, {
48
46
  render: function(args) {
49
-
50
47
  legend.innerHTML = "";
51
48
 
52
49
  var timestamp = document.createElement('div');
@@ -68,7 +65,6 @@ var realtimeGraph = function(updatePath) {
68
65
 
69
66
  line.appendChild(swatch);
70
67
  line.appendChild(label);
71
-
72
68
  legend.appendChild(line);
73
69
 
74
70
  var dot = document.createElement('div');
@@ -77,11 +73,8 @@ var realtimeGraph = function(updatePath) {
77
73
  dot.style.borderColor = d.series.color;
78
74
 
79
75
  this.element.appendChild(dot);
80
-
81
76
  dot.className = 'dot active';
82
-
83
77
  this.show();
84
-
85
78
  }, this );
86
79
  }
87
80
  });
@@ -90,7 +83,6 @@ var realtimeGraph = function(updatePath) {
90
83
  var i = 0;
91
84
  poller = setInterval(function() {
92
85
  $.getJSON($("#history").data("update-url"), function(data) {
93
-
94
86
  if (i === 0) {
95
87
  var processed = data.sidekiq.processed;
96
88
  var failed = data.sidekiq.failed;
@@ -144,7 +136,6 @@ var historyGraph = function() {
144
136
  ]
145
137
  } );
146
138
  var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } );
147
-
148
139
  var y_axis = new Rickshaw.Graph.Axis.Y({
149
140
  graph: graph,
150
141
  tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
@@ -156,7 +147,6 @@ var historyGraph = function() {
156
147
  var legend = document.querySelector('#history-legend');
157
148
  var Hover = Rickshaw.Class.create(Rickshaw.Graph.HoverDetail, {
158
149
  render: function(args) {
159
-
160
150
  legend.innerHTML = "";
161
151
 
162
152
  var timestamp = document.createElement('div');
@@ -178,7 +168,6 @@ var historyGraph = function() {
178
168
 
179
169
  line.appendChild(swatch);
180
170
  line.appendChild(label);
181
-
182
171
  legend.appendChild(line);
183
172
 
184
173
  var dot = document.createElement('div');
@@ -187,11 +176,8 @@ var historyGraph = function() {
187
176
  dot.style.borderColor = d.series.color;
188
177
 
189
178
  this.element.appendChild(dot);
190
-
191
179
  dot.className = 'dot active';
192
-
193
180
  this.show();
194
-
195
181
  }, this );
196
182
  }
197
183
  });
@@ -216,7 +202,6 @@ var updateStatsSummary = function(data) {
216
202
  $('ul.summary li.retries span.count').html(data.retries.numberWithDelimiter())
217
203
  $('ul.summary li.enqueued span.count').html(data.enqueued.numberWithDelimiter())
218
204
  $('ul.summary li.dead span.count').html(data.dead.numberWithDelimiter())
219
-
220
205
  }
221
206
 
222
207
  var updateRedisStats = function(data) {
@@ -277,7 +262,6 @@ $(function(){
277
262
  $(document).on('mousemove', 'div.interval-slider input', function(){
278
263
  setSliderLabel($(this).val());
279
264
  });
280
-
281
265
  });
282
266
 
283
267
  // Reset graphs
@@ -300,13 +284,10 @@ var debounce = function(fn, timeout)
300
284
 
301
285
  window.onresize = function() {
302
286
  var prevWidth = window.innerWidth;
303
-
304
287
  return debounce(function () {
305
288
  var currWidth = window.innerWidth;
306
-
307
289
  if (prevWidth !== currWidth) {
308
290
  prevWidth = currWidth;
309
-
310
291
  clearInterval(poller);
311
292
  resetGraphs();
312
293
  renderGraphs();