sidekiq 0.8.0 → 0.9.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 (66) hide show
  1. data/Changes.md +11 -0
  2. data/Gemfile +7 -1
  3. data/LICENSE +7 -1
  4. data/README.md +2 -0
  5. data/TODO.md +1 -2
  6. data/bin/sidekiq +1 -1
  7. data/config.ru +8 -0
  8. data/examples/config.yml +0 -2
  9. data/examples/scheduling.rb +37 -0
  10. data/lib/sidekiq.rb +25 -11
  11. data/lib/sidekiq/capistrano.rb +8 -5
  12. data/lib/sidekiq/cli.rb +20 -21
  13. data/lib/sidekiq/client.rb +9 -6
  14. data/lib/sidekiq/extensions/action_mailer.rb +1 -2
  15. data/lib/sidekiq/extensions/active_record.rb +1 -3
  16. data/lib/sidekiq/extensions/generic_proxy.rb +1 -1
  17. data/lib/sidekiq/manager.rb +28 -22
  18. data/lib/sidekiq/middleware/client/unique_jobs.rb +3 -3
  19. data/lib/sidekiq/middleware/server/failure_jobs.rb +1 -1
  20. data/lib/sidekiq/middleware/server/unique_jobs.rb +1 -1
  21. data/lib/sidekiq/processor.rb +4 -6
  22. data/lib/sidekiq/rails.rb +16 -1
  23. data/lib/sidekiq/redis_connection.rb +3 -3
  24. data/lib/sidekiq/util.rb +3 -15
  25. data/lib/sidekiq/version.rb +1 -1
  26. data/lib/sidekiq/web.rb +93 -0
  27. data/lib/sidekiq/worker.rb +0 -4
  28. data/myapp/Gemfile +15 -3
  29. data/myapp/app/controllers/work_controller.rb +1 -1
  30. data/myapp/config/initializers/sidekiq.rb +2 -2
  31. data/myapp/config/routes.rb +2 -2
  32. data/sidekiq.gemspec +3 -1
  33. data/test/helper.rb +4 -0
  34. data/test/test_cli.rb +26 -14
  35. data/test/test_client.rb +2 -2
  36. data/test/test_extensions.rb +11 -7
  37. data/test/test_manager.rb +2 -3
  38. data/test/test_middleware.rb +1 -1
  39. data/test/test_stats.rb +28 -29
  40. data/test/test_testing.rb +47 -14
  41. data/test/test_web.rb +51 -0
  42. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  43. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  44. data/web/assets/javascripts/application.js +3 -0
  45. data/web/assets/javascripts/vendor/bootstrap.js +12 -0
  46. data/web/assets/javascripts/vendor/bootstrap/bootstrap-alert.js +91 -0
  47. data/web/assets/javascripts/vendor/bootstrap/bootstrap-button.js +98 -0
  48. data/web/assets/javascripts/vendor/bootstrap/bootstrap-carousel.js +154 -0
  49. data/web/assets/javascripts/vendor/bootstrap/bootstrap-collapse.js +136 -0
  50. data/web/assets/javascripts/vendor/bootstrap/bootstrap-dropdown.js +92 -0
  51. data/web/assets/javascripts/vendor/bootstrap/bootstrap-modal.js +210 -0
  52. data/web/assets/javascripts/vendor/bootstrap/bootstrap-popover.js +95 -0
  53. data/web/assets/javascripts/vendor/bootstrap/bootstrap-scrollspy.js +125 -0
  54. data/web/assets/javascripts/vendor/bootstrap/bootstrap-tab.js +130 -0
  55. data/web/assets/javascripts/vendor/bootstrap/bootstrap-tooltip.js +270 -0
  56. data/web/assets/javascripts/vendor/bootstrap/bootstrap-transition.js +51 -0
  57. data/web/assets/javascripts/vendor/bootstrap/bootstrap-typeahead.js +271 -0
  58. data/web/assets/javascripts/vendor/jquery.js +9266 -0
  59. data/web/assets/stylesheets/application.css +11 -0
  60. data/web/assets/stylesheets/vendor/bootstrap-responsive.css +567 -0
  61. data/web/assets/stylesheets/vendor/bootstrap.css +3365 -0
  62. data/web/views/index.slim +42 -0
  63. data/web/views/layout.slim +24 -0
  64. data/web/views/queue.slim +11 -0
  65. metadata +71 -22
  66. data/lib/sidekiq/middleware/client/resque_web_compatibility.rb +0 -14
@@ -8,9 +8,8 @@ require 'connection_pool'
8
8
  class TestManager < MiniTest::Unit::TestCase
9
9
  describe 'with redis' do
10
10
  before do
11
- Sidekiq.redis = { :url => 'redis://localhost/sidekiq_test' }
12
- @redis = Sidekiq.redis
13
- @redis.flushdb
11
+ Sidekiq.redis = REDIS
12
+ Sidekiq.redis.flushdb
14
13
  $processed = 0
15
14
  $mutex = Mutex.new
16
15
  end
@@ -6,7 +6,7 @@ require 'sidekiq/processor'
6
6
  class TestMiddleware < MiniTest::Unit::TestCase
7
7
  describe 'middleware chain' do
8
8
  before do
9
- Sidekiq.redis = { :url => 'redis://localhost/sidekiq_test' }
9
+ Sidekiq.redis = REDIS
10
10
  end
11
11
 
12
12
  class CustomMiddleware
@@ -5,48 +5,50 @@ require 'sidekiq/processor'
5
5
  class TestStats < MiniTest::Unit::TestCase
6
6
  describe 'with redis' do
7
7
  before do
8
- Sidekiq.redis = { :url => 'redis://localhost/sidekiq_test' }
9
- @redis = Sidekiq.redis
10
- @redis.flushdb
8
+ @redis = Sidekiq.redis = REDIS
9
+ Sidekiq.redis.flushdb
11
10
  end
12
11
 
13
12
  class DumbWorker
14
13
  include Sidekiq::Worker
15
14
 
16
- def perform(redis)
17
- raise 'bang' if redis == nil
15
+ def perform(arg)
16
+ raise 'bang' if arg == nil
18
17
  end
19
18
  end
20
19
 
21
20
  it 'updates global stats in the success case' do
22
- msg = { 'class' => DumbWorker.to_s, 'args' => [@redis] }
21
+ msg = { 'class' => DumbWorker.to_s, 'args' => [""] }
23
22
  boss = MiniTest::Mock.new
24
23
 
25
- set = @redis.smembers('workers')
26
- assert_equal 0, set.size
24
+ @redis.with do |conn|
27
25
 
28
- processor = Sidekiq::Processor.new(boss)
29
- boss.expect(:processor_done!, nil, [processor])
26
+ set = conn.smembers('workers')
27
+ assert_equal 0, set.size
30
28
 
31
- # adds to the workers set upon initialize
32
- set = @redis.smembers('workers')
33
- assert_equal 1, set.size
34
- assert_match(/#{Regexp.escape(`hostname`.strip)}/, set.first)
29
+ processor = Sidekiq::Processor.new(boss)
30
+ boss.expect(:processor_done!, nil, [processor])
35
31
 
36
- assert_equal 0, @redis.get('stat:failed').to_i
37
- assert_equal 0, @redis.get('stat:processed').to_i
38
- assert_equal 0, @redis.get("stat:processed:#{processor}").to_i
32
+ # adds to the workers set upon initialize
33
+ set = conn.smembers('workers')
34
+ assert_equal 1, set.size
35
+ assert_match(/#{Regexp.escape(`hostname`.strip)}/, set.first)
39
36
 
40
- processor.process(msg, 'xyzzy')
41
- processor.process(msg, 'xyzzy')
42
- processor.process(msg, 'xyzzy')
37
+ assert_equal 0, conn.get('stat:failed').to_i
38
+ assert_equal 0, conn.get('stat:processed').to_i
39
+ assert_equal 0, conn.get("stat:processed:#{processor}").to_i
43
40
 
44
- set = @redis.smembers('workers')
45
- assert_equal 1, set.size
46
- assert_match(/#{Regexp.escape(`hostname`.strip)}/, set.first)
47
- assert_equal 0, @redis.get('stat:failed').to_i
48
- assert_equal 3, @redis.get('stat:processed').to_i
49
- assert_equal 3, @redis.get("stat:processed:#{processor}").to_i
41
+ processor.process(msg, 'xyzzy')
42
+ processor.process(msg, 'xyzzy')
43
+ processor.process(msg, 'xyzzy')
44
+
45
+ set = conn.smembers('workers')
46
+ assert_equal 1, set.size
47
+ assert_match(/#{Regexp.escape(`hostname`.strip)}/, set.first)
48
+ assert_equal 0, conn.get('stat:failed').to_i
49
+ assert_equal 3, conn.get('stat:processed').to_i
50
+ assert_equal 3, conn.get("stat:processed:#{processor}").to_i
51
+ end
50
52
  end
51
53
 
52
54
  it 'updates global stats in the error case' do
@@ -72,8 +74,5 @@ class TestStats < MiniTest::Unit::TestCase
72
74
  assert_equal nil, @redis.get("stat:processed:#{pstr}")
73
75
  end
74
76
 
75
- it 'should set various stats during processing' do
76
- skip 'TODO'
77
- end
78
77
  end
79
78
  end
@@ -1,5 +1,12 @@
1
1
  require 'helper'
2
+ require 'sidekiq'
2
3
  require 'sidekiq/worker'
4
+ require 'active_record'
5
+ require 'action_mailer'
6
+ require 'sidekiq/extensions/action_mailer'
7
+ require 'sidekiq/extensions/active_record'
8
+
9
+ Sidekiq.hook_rails!
3
10
 
4
11
  class TestTesting < MiniTest::Unit::TestCase
5
12
  describe 'sidekiq testing' do
@@ -11,22 +18,48 @@ class TestTesting < MiniTest::Unit::TestCase
11
18
  end
12
19
  end
13
20
 
14
- it 'stubs the async call when in testing mode' do
15
- begin
16
- # Override Sidekiq::Worker
17
- require 'sidekiq/testing'
18
- assert_equal 0, DirectWorker.jobs.size
19
- assert DirectWorker.perform_async(1, 2)
20
- assert_equal 1, DirectWorker.jobs.size
21
- ensure
22
- # Undo override
23
- Sidekiq::Worker::ClassMethods.class_eval do
24
- remove_method :perform_async
25
- alias_method :perform_async, :perform_async_old
26
- remove_method :perform_async_old
27
- end
21
+ class FooMailer < ActionMailer::Base
22
+ def bar(str)
23
+ str
24
+ end
25
+ end
26
+
27
+ class FooModel < ActiveRecord::Base
28
+ def bar(str)
29
+ str
28
30
  end
29
31
  end
30
32
 
33
+ before do
34
+ require 'sidekiq/testing'
35
+ end
36
+
37
+ after do
38
+ # Undo override
39
+ Sidekiq::Worker::ClassMethods.class_eval do
40
+ remove_method :perform_async
41
+ alias_method :perform_async, :perform_async_old
42
+ remove_method :perform_async_old
43
+ end
44
+ end
45
+
46
+ it 'stubs the async call when in testing mode' do
47
+ # We can only have one it block here so all 'testing' tests
48
+ # have to go here because require 'sidekiq/testing' changes
49
+ # how Sidekiq works and we need to roll back those changes
50
+ # when the test is done.
51
+ assert_equal 0, DirectWorker.jobs.size
52
+ assert DirectWorker.perform_async(1, 2)
53
+ assert_equal 1, DirectWorker.jobs.size
54
+
55
+ assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
56
+ FooMailer.delay.bar('hello!')
57
+ assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
58
+
59
+ assert_equal 0, Sidekiq::Extensions::DelayedModel.jobs.size
60
+ FooModel.delay.bar('hello!')
61
+ assert_equal 1, Sidekiq::Extensions::DelayedModel.jobs.size
62
+ end
63
+
31
64
  end
32
65
  end
@@ -0,0 +1,51 @@
1
+ require 'helper'
2
+ require 'sidekiq'
3
+ require 'sidekiq/web'
4
+ require 'rack/test'
5
+
6
+ class TestWeb < MiniTest::Unit::TestCase
7
+ describe 'sidekiq web' do
8
+ include Rack::Test::Methods
9
+
10
+ def app
11
+ Sidekiq::Web
12
+ end
13
+
14
+ before do
15
+ Sidekiq.redis = REDIS
16
+ Sidekiq.redis.flushdb
17
+ end
18
+
19
+ class WebWorker
20
+ include Sidekiq::Worker
21
+
22
+ def perform(a, b)
23
+ a + b
24
+ end
25
+ end
26
+
27
+ it 'shows active queues' do
28
+ get '/'
29
+ assert_equal 200, last_response.status
30
+ assert_match last_response.body, /Sidekiq is down/
31
+ refute_match last_response.body, /default/
32
+
33
+ assert WebWorker.perform_async(1, 2)
34
+
35
+ get '/'
36
+ assert_equal 200, last_response.status
37
+ assert_match last_response.body, /Sidekiq is down/
38
+ assert_match last_response.body, /default/
39
+ refute_match last_response.body, /foo/
40
+
41
+ assert Sidekiq::Client.push(:foo, 'class' => WebWorker, 'args' => [1, 3])
42
+
43
+ get '/'
44
+ assert_equal 200, last_response.status
45
+ assert_match last_response.body, /Sidekiq is down/
46
+ assert_match last_response.body, /default/
47
+ assert_match last_response.body, /foo/
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,3 @@
1
+ //= require vendor/jquery
2
+ //= require bootstrap
3
+ //= require_tree .
@@ -0,0 +1,12 @@
1
+ //= require vendor/bootstrap/bootstrap-transition
2
+ //= require vendor/bootstrap/bootstrap-alert
3
+ //= require vendor/bootstrap/bootstrap-modal
4
+ //= require vendor/bootstrap/bootstrap-dropdown
5
+ //= require vendor/bootstrap/bootstrap-scrollspy
6
+ //= require vendor/bootstrap/bootstrap-tab
7
+ //= require vendor/bootstrap/bootstrap-tooltip
8
+ //= require vendor/bootstrap/bootstrap-popover
9
+ //= require vendor/bootstrap/bootstrap-button
10
+ //= require vendor/bootstrap/bootstrap-collapse
11
+ //= require vendor/bootstrap/bootstrap-carousel
12
+ //= require vendor/bootstrap/bootstrap-typeahead
@@ -0,0 +1,91 @@
1
+ /* ==========================================================
2
+ * bootstrap-alert.js v2.0.0
3
+ * http://twitter.github.com/bootstrap/javascript.html#alerts
4
+ * ==========================================================
5
+ * Copyright 2012 Twitter, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ * ========================================================== */
19
+
20
+
21
+ !function( $ ){
22
+
23
+ "use strict"
24
+
25
+ /* ALERT CLASS DEFINITION
26
+ * ====================== */
27
+
28
+ var dismiss = '[data-dismiss="alert"]'
29
+ , Alert = function ( el ) {
30
+ $(el).on('click', dismiss, this.close)
31
+ }
32
+
33
+ Alert.prototype = {
34
+
35
+ constructor: Alert
36
+
37
+ , close: function ( e ) {
38
+ var $this = $(this)
39
+ , selector = $this.attr('data-target')
40
+ , $parent
41
+
42
+ if (!selector) {
43
+ selector = $this.attr('href')
44
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
45
+ }
46
+
47
+ $parent = $(selector)
48
+ $parent.trigger('close')
49
+
50
+ e && e.preventDefault()
51
+
52
+ $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
53
+
54
+ $parent.removeClass('in')
55
+
56
+ function removeElement() {
57
+ $parent.remove()
58
+ $parent.trigger('closed')
59
+ }
60
+
61
+ $.support.transition && $parent.hasClass('fade') ?
62
+ $parent.on($.support.transition.end, removeElement) :
63
+ removeElement()
64
+ }
65
+
66
+ }
67
+
68
+
69
+ /* ALERT PLUGIN DEFINITION
70
+ * ======================= */
71
+
72
+ $.fn.alert = function ( option ) {
73
+ return this.each(function () {
74
+ var $this = $(this)
75
+ , data = $this.data('alert')
76
+ if (!data) $this.data('alert', (data = new Alert(this)))
77
+ if (typeof option == 'string') data[option].call($this)
78
+ })
79
+ }
80
+
81
+ $.fn.alert.Constructor = Alert
82
+
83
+
84
+ /* ALERT DATA-API
85
+ * ============== */
86
+
87
+ $(function () {
88
+ $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
89
+ })
90
+
91
+ }( window.jQuery )
@@ -0,0 +1,98 @@
1
+ /* ============================================================
2
+ * bootstrap-button.js v2.0.0
3
+ * http://twitter.github.com/bootstrap/javascript.html#buttons
4
+ * ============================================================
5
+ * Copyright 2012 Twitter, Inc.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the "License");
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ * ============================================================ */
19
+
20
+ !function( $ ){
21
+
22
+ "use strict"
23
+
24
+ /* BUTTON PUBLIC CLASS DEFINITION
25
+ * ============================== */
26
+
27
+ var Button = function ( element, options ) {
28
+ this.$element = $(element)
29
+ this.options = $.extend({}, $.fn.button.defaults, options)
30
+ }
31
+
32
+ Button.prototype = {
33
+
34
+ constructor: Button
35
+
36
+ , setState: function ( state ) {
37
+ var d = 'disabled'
38
+ , $el = this.$element
39
+ , data = $el.data()
40
+ , val = $el.is('input') ? 'val' : 'html'
41
+
42
+ state = state + 'Text'
43
+ data.resetText || $el.data('resetText', $el[val]())
44
+
45
+ $el[val](data[state] || this.options[state])
46
+
47
+ // push to event loop to allow forms to submit
48
+ setTimeout(function () {
49
+ state == 'loadingText' ?
50
+ $el.addClass(d).attr(d, d) :
51
+ $el.removeClass(d).removeAttr(d)
52
+ }, 0)
53
+ }
54
+
55
+ , toggle: function () {
56
+ var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
57
+
58
+ $parent && $parent
59
+ .find('.active')
60
+ .removeClass('active')
61
+
62
+ this.$element.toggleClass('active')
63
+ }
64
+
65
+ }
66
+
67
+
68
+ /* BUTTON PLUGIN DEFINITION
69
+ * ======================== */
70
+
71
+ $.fn.button = function ( option ) {
72
+ return this.each(function () {
73
+ var $this = $(this)
74
+ , data = $this.data('button')
75
+ , options = typeof option == 'object' && option
76
+ if (!data) $this.data('button', (data = new Button(this, options)))
77
+ if (option == 'toggle') data.toggle()
78
+ else if (option) data.setState(option)
79
+ })
80
+ }
81
+
82
+ $.fn.button.defaults = {
83
+ loadingText: 'loading...'
84
+ }
85
+
86
+ $.fn.button.Constructor = Button
87
+
88
+
89
+ /* BUTTON DATA-API
90
+ * =============== */
91
+
92
+ $(function () {
93
+ $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {
94
+ $(e.target).button('toggle')
95
+ })
96
+ })
97
+
98
+ }( window.jQuery )