kulesa-sidekiq 1.2.2

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.
Files changed (135) hide show
  1. data/.gitignore +6 -0
  2. data/.rvmrc +4 -0
  3. data/COMM-LICENSE +83 -0
  4. data/Changes.md +207 -0
  5. data/Gemfile +12 -0
  6. data/LICENSE +22 -0
  7. data/README.md +61 -0
  8. data/Rakefile +9 -0
  9. data/bin/client +7 -0
  10. data/bin/sidekiq +14 -0
  11. data/bin/sidekiqctl +74 -0
  12. data/config.ru +18 -0
  13. data/examples/chef/cookbooks/sidekiq/README.rdoc +11 -0
  14. data/examples/chef/cookbooks/sidekiq/recipes/default.rb +55 -0
  15. data/examples/chef/cookbooks/sidekiq/templates/default/monitrc.conf.erb +8 -0
  16. data/examples/chef/cookbooks/sidekiq/templates/default/sidekiq.erb +219 -0
  17. data/examples/chef/cookbooks/sidekiq/templates/default/sidekiq.yml.erb +22 -0
  18. data/examples/clockwork.rb +44 -0
  19. data/examples/config.yml +10 -0
  20. data/examples/monitrc.conf +6 -0
  21. data/examples/por.rb +27 -0
  22. data/examples/scheduling.rb +37 -0
  23. data/examples/sinkiq.rb +59 -0
  24. data/examples/web-ui.png +0 -0
  25. data/lib/sidekiq.rb +98 -0
  26. data/lib/sidekiq/capistrano.rb +35 -0
  27. data/lib/sidekiq/cli.rb +214 -0
  28. data/lib/sidekiq/client.rb +72 -0
  29. data/lib/sidekiq/extensions/action_mailer.rb +26 -0
  30. data/lib/sidekiq/extensions/active_record.rb +27 -0
  31. data/lib/sidekiq/extensions/generic_proxy.rb +21 -0
  32. data/lib/sidekiq/fetch.rb +76 -0
  33. data/lib/sidekiq/logging.rb +46 -0
  34. data/lib/sidekiq/manager.rb +163 -0
  35. data/lib/sidekiq/middleware/chain.rb +96 -0
  36. data/lib/sidekiq/middleware/client/unique_jobs.rb +36 -0
  37. data/lib/sidekiq/middleware/server/active_record.rb +13 -0
  38. data/lib/sidekiq/middleware/server/exception_handler.rb +38 -0
  39. data/lib/sidekiq/middleware/server/failure_jobs.rb +25 -0
  40. data/lib/sidekiq/middleware/server/logging.rb +31 -0
  41. data/lib/sidekiq/middleware/server/retry_jobs.rb +69 -0
  42. data/lib/sidekiq/middleware/server/timeout.rb +21 -0
  43. data/lib/sidekiq/middleware/server/unique_jobs.rb +17 -0
  44. data/lib/sidekiq/processor.rb +92 -0
  45. data/lib/sidekiq/rails.rb +21 -0
  46. data/lib/sidekiq/redis_connection.rb +27 -0
  47. data/lib/sidekiq/retry.rb +59 -0
  48. data/lib/sidekiq/testing.rb +44 -0
  49. data/lib/sidekiq/testing/inline.rb +37 -0
  50. data/lib/sidekiq/util.rb +40 -0
  51. data/lib/sidekiq/version.rb +3 -0
  52. data/lib/sidekiq/web.rb +185 -0
  53. data/lib/sidekiq/worker.rb +62 -0
  54. data/lib/sidekiq/yaml_patch.rb +21 -0
  55. data/myapp/.gitignore +15 -0
  56. data/myapp/Capfile +5 -0
  57. data/myapp/Gemfile +19 -0
  58. data/myapp/Rakefile +7 -0
  59. data/myapp/app/controllers/application_controller.rb +3 -0
  60. data/myapp/app/controllers/work_controller.rb +38 -0
  61. data/myapp/app/helpers/application_helper.rb +2 -0
  62. data/myapp/app/mailers/.gitkeep +0 -0
  63. data/myapp/app/mailers/user_mailer.rb +9 -0
  64. data/myapp/app/models/.gitkeep +0 -0
  65. data/myapp/app/models/post.rb +5 -0
  66. data/myapp/app/views/layouts/application.html.erb +14 -0
  67. data/myapp/app/views/user_mailer/greetings.html.erb +3 -0
  68. data/myapp/app/views/work/index.html.erb +1 -0
  69. data/myapp/app/workers/hard_worker.rb +10 -0
  70. data/myapp/config.ru +4 -0
  71. data/myapp/config/application.rb +59 -0
  72. data/myapp/config/boot.rb +6 -0
  73. data/myapp/config/database.yml +25 -0
  74. data/myapp/config/deploy.rb +15 -0
  75. data/myapp/config/environment.rb +5 -0
  76. data/myapp/config/environments/development.rb +38 -0
  77. data/myapp/config/environments/production.rb +67 -0
  78. data/myapp/config/environments/test.rb +37 -0
  79. data/myapp/config/initializers/backtrace_silencers.rb +7 -0
  80. data/myapp/config/initializers/inflections.rb +15 -0
  81. data/myapp/config/initializers/mime_types.rb +5 -0
  82. data/myapp/config/initializers/secret_token.rb +7 -0
  83. data/myapp/config/initializers/session_store.rb +8 -0
  84. data/myapp/config/initializers/sidekiq.rb +6 -0
  85. data/myapp/config/initializers/wrap_parameters.rb +14 -0
  86. data/myapp/config/locales/en.yml +5 -0
  87. data/myapp/config/routes.rb +10 -0
  88. data/myapp/db/migrate/20120123214055_create_posts.rb +10 -0
  89. data/myapp/db/seeds.rb +7 -0
  90. data/myapp/lib/assets/.gitkeep +0 -0
  91. data/myapp/lib/tasks/.gitkeep +0 -0
  92. data/myapp/log/.gitkeep +0 -0
  93. data/myapp/script/rails +6 -0
  94. data/sidekiq.gemspec +27 -0
  95. data/test/config.yml +9 -0
  96. data/test/fake_env.rb +0 -0
  97. data/test/helper.rb +16 -0
  98. data/test/test_cli.rb +168 -0
  99. data/test/test_client.rb +119 -0
  100. data/test/test_extensions.rb +69 -0
  101. data/test/test_manager.rb +51 -0
  102. data/test/test_middleware.rb +92 -0
  103. data/test/test_processor.rb +32 -0
  104. data/test/test_retry.rb +125 -0
  105. data/test/test_stats.rb +68 -0
  106. data/test/test_testing.rb +97 -0
  107. data/test/test_testing_inline.rb +75 -0
  108. data/test/test_web.rb +122 -0
  109. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  110. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  111. data/web/assets/javascripts/application.js +20 -0
  112. data/web/assets/javascripts/vendor/bootstrap.js +12 -0
  113. data/web/assets/javascripts/vendor/bootstrap/bootstrap-alert.js +91 -0
  114. data/web/assets/javascripts/vendor/bootstrap/bootstrap-button.js +98 -0
  115. data/web/assets/javascripts/vendor/bootstrap/bootstrap-carousel.js +154 -0
  116. data/web/assets/javascripts/vendor/bootstrap/bootstrap-collapse.js +136 -0
  117. data/web/assets/javascripts/vendor/bootstrap/bootstrap-dropdown.js +92 -0
  118. data/web/assets/javascripts/vendor/bootstrap/bootstrap-modal.js +210 -0
  119. data/web/assets/javascripts/vendor/bootstrap/bootstrap-popover.js +95 -0
  120. data/web/assets/javascripts/vendor/bootstrap/bootstrap-scrollspy.js +125 -0
  121. data/web/assets/javascripts/vendor/bootstrap/bootstrap-tab.js +130 -0
  122. data/web/assets/javascripts/vendor/bootstrap/bootstrap-tooltip.js +270 -0
  123. data/web/assets/javascripts/vendor/bootstrap/bootstrap-transition.js +51 -0
  124. data/web/assets/javascripts/vendor/bootstrap/bootstrap-typeahead.js +271 -0
  125. data/web/assets/javascripts/vendor/jquery.js +9266 -0
  126. data/web/assets/javascripts/vendor/jquery.timeago.js +148 -0
  127. data/web/assets/stylesheets/application.css +27 -0
  128. data/web/assets/stylesheets/vendor/bootstrap-responsive.css +567 -0
  129. data/web/assets/stylesheets/vendor/bootstrap.css +3365 -0
  130. data/web/views/index.slim +48 -0
  131. data/web/views/layout.slim +26 -0
  132. data/web/views/queue.slim +11 -0
  133. data/web/views/retries.slim +29 -0
  134. data/web/views/retry.slim +52 -0
  135. metadata +371 -0
@@ -0,0 +1,44 @@
1
+ module Sidekiq
2
+ module Worker
3
+
4
+ ##
5
+ # The Sidekiq testing infrastructure overrides perform_async
6
+ # so that it does not actually touch the network. Instead it
7
+ # stores the asynchronous jobs in a per-class array so that
8
+ # their presence/absence can be asserted by your tests.
9
+ #
10
+ # This is similar to ActionMailer's :test delivery_method and its
11
+ # ActionMailer::Base.deliveries array.
12
+ #
13
+ # Example:
14
+ #
15
+ # require 'sidekiq/testing'
16
+ #
17
+ # assert_equal 0, HardWorker.jobs.size
18
+ # HardWorker.perform_async(:something)
19
+ # assert_equal 1, HardWorker.jobs.size
20
+ # assert_equal :something, HardWorker.jobs[0]['args'][0]
21
+ #
22
+ # assert_equal 0, Sidekiq::Extensions::DelayedMailer.jobs.size
23
+ # MyMailer.delayed.send_welcome_email('foo@example.com')
24
+ # assert_equal 1, Sidekiq::Extensions::DelayedMailer.jobs.size
25
+ #
26
+ module ClassMethods
27
+ alias_method :perform_async_old, :perform_async
28
+ def perform_async(*args)
29
+ jobs << { 'class' => self.name, 'args' => args }
30
+ true
31
+ end
32
+
33
+ def jobs
34
+ @pushed ||= []
35
+ end
36
+
37
+ def drain
38
+ while job = jobs.shift do
39
+ new.perform(*job['args'])
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,37 @@
1
+ module Sidekiq
2
+ module Worker
3
+
4
+ ##
5
+ # The Sidekiq inline infrastructure overrides the perform_async so that it
6
+ # actually calls perform instead. This allows workers to be run inline in a
7
+ # testing environment.
8
+ #
9
+ # This is similar to `Resque.inline = true` functionality.
10
+ #
11
+ # Example:
12
+ #
13
+ # require 'sidekiq/testing/inline'
14
+ #
15
+ # $external_variable = 0
16
+ #
17
+ # class ExternalWorker
18
+ # include Sidekiq::Worker
19
+ #
20
+ # def perform
21
+ # $external_variable = 1
22
+ # end
23
+ # end
24
+ #
25
+ # assert_equal 0, $external_variable
26
+ # ExternalWorker.perform_async
27
+ # assert_equal 1, $external_variable
28
+ #
29
+ module ClassMethods
30
+ alias_method :perform_async_old, :perform_async
31
+ def perform_async(*args)
32
+ new.perform(*args)
33
+ true
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,40 @@
1
+ module Sidekiq
2
+ ##
3
+ # This module is part of Sidekiq core and not intended for extensions.
4
+ #
5
+ module Util
6
+
7
+ EXPIRY = 60 * 60
8
+
9
+ def constantize(camel_cased_word)
10
+ names = camel_cased_word.split('::')
11
+ names.shift if names.empty? || names.first.empty?
12
+
13
+ constant = Object
14
+ names.each do |name|
15
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
16
+ end
17
+ constant
18
+ end
19
+
20
+ def watchdog(last_words)
21
+ yield
22
+ rescue => ex
23
+ logger.error last_words
24
+ logger.error ex
25
+ logger.error ex.backtrace.join("\n")
26
+ end
27
+
28
+ def logger
29
+ Sidekiq.logger
30
+ end
31
+
32
+ def redis(&block)
33
+ Sidekiq.redis(&block)
34
+ end
35
+
36
+ def process_id
37
+ Process.pid
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module Sidekiq
2
+ VERSION = "1.2.2"
3
+ end
@@ -0,0 +1,185 @@
1
+ require 'sinatra/base'
2
+ require 'slim'
3
+ require 'sprockets'
4
+ require 'multi_json'
5
+
6
+ module Sidekiq
7
+ class SprocketsMiddleware
8
+ def initialize(app, options={})
9
+ @app = app
10
+ @root = options[:root]
11
+ path = options[:path] || 'assets'
12
+ @matcher = /^\/#{path}\/*/
13
+ @environment = ::Sprockets::Environment.new(@root)
14
+ @environment.append_path 'assets/javascripts'
15
+ @environment.append_path 'assets/javascripts/vendor'
16
+ @environment.append_path 'assets/stylesheets'
17
+ @environment.append_path 'assets/stylesheets/vendor'
18
+ @environment.append_path 'assets/images'
19
+ end
20
+
21
+ def call(env)
22
+ # Solve the problem of people requesting /sidekiq when they need to request /sidekiq/ so
23
+ # that relative links in templates resolve correctly.
24
+ return [301, { 'Location' => "#{env['SCRIPT_NAME']}/", 'Content-Type' => 'text/html' }, ['redirecting']] if env['SCRIPT_NAME'] == env['REQUEST_PATH']
25
+
26
+ return @app.call(env) unless @matcher =~ env["PATH_INFO"]
27
+ env['PATH_INFO'].sub!(@matcher,'')
28
+ @environment.call(env)
29
+ end
30
+ end
31
+
32
+ class Web < Sinatra::Base
33
+ dir = File.expand_path(File.dirname(__FILE__) + "/../../web")
34
+ set :views, "#{dir}/views"
35
+ set :root, "#{dir}/public"
36
+ set :slim, :pretty => true
37
+ use SprocketsMiddleware, :root => dir
38
+
39
+ helpers do
40
+
41
+ def workers
42
+ @workers ||= begin
43
+ Sidekiq.redis do |conn|
44
+ conn.smembers('workers').map do |w|
45
+ msg = conn.get("worker:#{w}")
46
+ msg ? [w, Sidekiq.load_json(msg)] : nil
47
+ end.compact.sort { |x| x[1] ? -1 : 1 }
48
+ end
49
+ end
50
+ end
51
+
52
+ def processed
53
+ Sidekiq.redis { |conn| conn.get('stat:processed') } || 0
54
+ end
55
+
56
+ def failed
57
+ Sidekiq.redis { |conn| conn.get('stat:failed') } || 0
58
+ end
59
+
60
+ def retry_count
61
+ Sidekiq.redis { |conn| conn.zcard('retry') }
62
+ end
63
+
64
+ def retries(count=50)
65
+ Sidekiq.redis do |conn|
66
+ results = conn.zrange('retry', 0, count, :withscores => true)
67
+ results.each_slice(2).map { |msg, score| [Sidekiq.load_json(msg), Float(score)] }
68
+ end
69
+ end
70
+
71
+ def queues
72
+ @queues ||= Sidekiq.redis do |conn|
73
+ conn.smembers('queues').map do |q|
74
+ [q, conn.llen("queue:#{q}") || 0]
75
+ end.sort { |x,y| x[1] <=> y[1] }
76
+ end
77
+ end
78
+
79
+ def retries_with_score(score)
80
+ Sidekiq.redis do |conn|
81
+ results = conn.zrangebyscore('retry', score, score)
82
+ results.map { |msg| Sidekiq.load_json(msg) }
83
+ end
84
+ end
85
+
86
+ def location
87
+ Sidekiq.redis { |conn| conn.client.location }
88
+ end
89
+
90
+ def root_path
91
+ "#{env['SCRIPT_NAME']}/"
92
+ end
93
+
94
+ def current_status
95
+ return 'idle' if workers.size == 0
96
+ return 'active'
97
+ end
98
+
99
+ def relative_time(time)
100
+ %{<time datetime="#{time.getutc.iso8601}">#{time}</time>}
101
+ end
102
+
103
+ def display_args(args, count=100)
104
+ args.map { |arg| a = arg.inspect; a.size > count ? "#{a[0..count]}..." : a }.join(", ")
105
+ end
106
+ end
107
+
108
+ get "/" do
109
+ slim :index
110
+ end
111
+
112
+ get "/queues/:name" do
113
+ halt 404 unless params[:name]
114
+ count = (params[:count] || 10).to_i
115
+ @name = params[:name]
116
+ @messages = Sidekiq.redis {|conn| conn.lrange("queue:#{@name}", 0, count) }.map { |str| Sidekiq.load_json(str) }
117
+ slim :queue
118
+ end
119
+
120
+ post "/queues/:name" do
121
+ Sidekiq.redis do |conn|
122
+ conn.del("queue:#{params[:name]}")
123
+ conn.srem("queues", params[:name])
124
+ end
125
+ redirect root_path
126
+ end
127
+
128
+ get "/retries/:score" do
129
+ halt 404 unless params[:score]
130
+ @score = params[:score].to_f
131
+ @retries = retries_with_score(@score)
132
+ redirect "#{root_path}retries" if @retries.empty?
133
+ slim :retry
134
+ end
135
+
136
+ get '/retries' do
137
+ @retries = retries
138
+ slim :retries
139
+ end
140
+
141
+ post '/retries' do
142
+ halt 404 unless params[:score]
143
+ params[:score].each do |score|
144
+ s = score.to_f
145
+ if params['retry']
146
+ process_score(s, :retry)
147
+ elsif params['delete']
148
+ process_score(s, :delete)
149
+ end
150
+ end
151
+ redirect root_path
152
+ end
153
+
154
+ post "/retries/:score" do
155
+ halt 404 unless params[:score]
156
+ score = params[:score].to_f
157
+ if params['retry']
158
+ process_score(score, :retry)
159
+ elsif params['delete']
160
+ process_score(score, :delete)
161
+ end
162
+ redirect root_path
163
+ end
164
+
165
+ def process_score(score, operation)
166
+ case operation
167
+ when :retry
168
+ Sidekiq.redis do |conn|
169
+ results = conn.zrangebyscore('retry', score, score)
170
+ conn.zremrangebyscore('retry', score, score)
171
+ results.map do |message|
172
+ msg = Sidekiq.load_json(message)
173
+ conn.rpush("queue:#{msg['queue']}", message)
174
+ end
175
+ end
176
+ when :delete
177
+ Sidekiq.redis do |conn|
178
+ conn.zremrangebyscore('retry', score, score)
179
+ end
180
+ end
181
+ end
182
+
183
+ end
184
+
185
+ end
@@ -0,0 +1,62 @@
1
+ require 'sidekiq/client'
2
+
3
+ module Sidekiq
4
+
5
+ ##
6
+ # Include this module in your worker class and you can easily create
7
+ # asynchronous jobs:
8
+ #
9
+ # class HardWorker
10
+ # include Sidekiq::Worker
11
+ #
12
+ # def perform(*args)
13
+ # # do some work
14
+ # end
15
+ # end
16
+ #
17
+ # Then in your Rails app, you can do this:
18
+ #
19
+ # HardWorker.perform_async(1, 2, 3)
20
+ #
21
+ # Note that perform_async is a class method, perform is an instance method.
22
+ module Worker
23
+ def self.included(base)
24
+ base.extend(ClassMethods)
25
+ end
26
+
27
+ def logger
28
+ Sidekiq.logger
29
+ end
30
+
31
+ module ClassMethods
32
+ def perform_async(*args)
33
+ Sidekiq::Client.push('class' => self, 'args' => args)
34
+ end
35
+
36
+ ##
37
+ # Allows customization for this type of Worker.
38
+ # Legal options:
39
+ #
40
+ # :unique - enable the UniqueJobs middleware for this Worker, default *true*
41
+ # :queue - use a named queue for this Worker, default 'default'
42
+ # :retry - enable the RetryJobs middleware for this Worker, default *true*
43
+ # :timeout - timeout the perform method after N seconds, default *nil*
44
+ # :backtrace - whether to save any error backtrace in the retry payload to display in web UI,
45
+ # can be true, false or an integer number of lines to save, default *false*
46
+ def sidekiq_options(opts={})
47
+ @sidekiq_options = get_sidekiq_options.merge(stringify_keys(opts || {}))
48
+ end
49
+
50
+ def get_sidekiq_options # :nodoc:
51
+ defined?(@sidekiq_options) ? @sidekiq_options : { 'unique' => true, 'retry' => true, 'queue' => 'default' }
52
+ end
53
+
54
+ def stringify_keys(hash) # :nodoc:
55
+ hash.keys.each do |key|
56
+ hash[key.to_s] = hash.delete(key)
57
+ end
58
+ hash
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,21 @@
1
+ # YAML marshalling of instances can fail in some circumstances,
2
+ # e.g. when the instance has a handle to a Proc. This monkeypatch limits
3
+ # the YAML serialization to just AR's internal @attributes hash.
4
+ # The paperclip gem litters AR instances with Procs, for instance.
5
+ #
6
+ # Courtesy of @ryanlecompte https://gist.github.com/007b88ae90372d1a3321
7
+ #
8
+
9
+ if defined?(::ActiveRecord)
10
+ class ActiveRecord::Base
11
+ yaml_as "tag:ruby.yaml.org,2002:ActiveRecord"
12
+
13
+ def self.yaml_new(klass, tag, val)
14
+ klass.unscoped.find(val['attributes'][klass.primary_key])
15
+ end
16
+
17
+ def to_yaml_properties
18
+ ['@attributes']
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile ~/.gitignore_global
6
+
7
+ # Ignore bundler config
8
+ /.bundle
9
+
10
+ # Ignore the default SQLite database.
11
+ /db/*.sqlite3
12
+
13
+ # Ignore all logfiles and tempfiles.
14
+ /log/*.log
15
+ /tmp
@@ -0,0 +1,5 @@
1
+ load 'deploy'
2
+ # Uncomment if you are using Rails' asset pipeline
3
+ # load 'deploy/assets'
4
+ Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
5
+ load 'config/deploy' # remove this line to skip loading any of the default tasks
@@ -0,0 +1,19 @@
1
+ source 'https://rubygems.org'
2
+
3
+ platforms :ruby do
4
+ gem 'sqlite3'
5
+ end
6
+
7
+ platforms :jruby do
8
+ gem 'jruby-openssl'
9
+ gem 'activerecord-jdbcsqlite3-adapter'
10
+ end
11
+
12
+ gem 'rails', '3.2.2'
13
+ gem 'sidekiq', :path => '..'
14
+ gem 'capistrano'
15
+
16
+ # sidekiq-web dependencies
17
+ gem 'slim'
18
+ gem 'sinatra'
19
+ gem 'sprockets'
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
3
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
+
5
+ require File.expand_path('../config/application', __FILE__)
6
+
7
+ Myapp::Application.load_tasks