sr-sidekiq 4.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/3.0-Upgrade.md +70 -0
  4. data/4.0-Upgrade.md +50 -0
  5. data/COMM-LICENSE (sidekiq) +95 -0
  6. data/Changes.md +1241 -0
  7. data/Ent-Changes.md +112 -0
  8. data/Gemfile +29 -0
  9. data/LICENSE (sidekiq) +9 -0
  10. data/LICENSE (sr-sidekiq) +5 -0
  11. data/Pro-2.0-Upgrade.md +138 -0
  12. data/Pro-3.0-Upgrade.md +44 -0
  13. data/Pro-Changes.md +539 -0
  14. data/README.md +8 -0
  15. data/Rakefile +9 -0
  16. data/bin/sidekiq +18 -0
  17. data/bin/sidekiqctl +99 -0
  18. data/bin/sidekiqload +167 -0
  19. data/code_of_conduct.md +50 -0
  20. data/lib/generators/sidekiq/templates/worker.rb.erb +9 -0
  21. data/lib/generators/sidekiq/templates/worker_spec.rb.erb +6 -0
  22. data/lib/generators/sidekiq/templates/worker_test.rb.erb +8 -0
  23. data/lib/generators/sidekiq/worker_generator.rb +49 -0
  24. data/lib/sidekiq.rb +237 -0
  25. data/lib/sidekiq/api.rb +844 -0
  26. data/lib/sidekiq/cli.rb +389 -0
  27. data/lib/sidekiq/client.rb +260 -0
  28. data/lib/sidekiq/core_ext.rb +106 -0
  29. data/lib/sidekiq/exception_handler.rb +31 -0
  30. data/lib/sidekiq/extensions/action_mailer.rb +57 -0
  31. data/lib/sidekiq/extensions/active_record.rb +40 -0
  32. data/lib/sidekiq/extensions/class_methods.rb +40 -0
  33. data/lib/sidekiq/extensions/generic_proxy.rb +25 -0
  34. data/lib/sidekiq/fetch.rb +81 -0
  35. data/lib/sidekiq/launcher.rb +160 -0
  36. data/lib/sidekiq/logging.rb +106 -0
  37. data/lib/sidekiq/manager.rb +137 -0
  38. data/lib/sidekiq/middleware/chain.rb +150 -0
  39. data/lib/sidekiq/middleware/i18n.rb +42 -0
  40. data/lib/sidekiq/middleware/server/active_record.rb +13 -0
  41. data/lib/sidekiq/middleware/server/logging.rb +40 -0
  42. data/lib/sidekiq/middleware/server/retry_jobs.rb +205 -0
  43. data/lib/sidekiq/paginator.rb +43 -0
  44. data/lib/sidekiq/processor.rb +186 -0
  45. data/lib/sidekiq/rails.rb +39 -0
  46. data/lib/sidekiq/redis_connection.rb +97 -0
  47. data/lib/sidekiq/scheduled.rb +146 -0
  48. data/lib/sidekiq/testing.rb +316 -0
  49. data/lib/sidekiq/testing/inline.rb +29 -0
  50. data/lib/sidekiq/util.rb +62 -0
  51. data/lib/sidekiq/version.rb +4 -0
  52. data/lib/sidekiq/web.rb +278 -0
  53. data/lib/sidekiq/web_helpers.rb +255 -0
  54. data/lib/sidekiq/worker.rb +121 -0
  55. data/sidekiq.gemspec +26 -0
  56. data/sr-sidekiq-4.1.3.gem +0 -0
  57. data/sr-sidekiq-4.1.4.gem +0 -0
  58. data/sr-sidekiq-4.1.5.gem +0 -0
  59. data/test/config.yml +9 -0
  60. data/test/env_based_config.yml +11 -0
  61. data/test/fake_env.rb +1 -0
  62. data/test/fixtures/en.yml +2 -0
  63. data/test/helper.rb +75 -0
  64. data/test/test_actors.rb +138 -0
  65. data/test/test_api.rb +528 -0
  66. data/test/test_cli.rb +406 -0
  67. data/test/test_client.rb +262 -0
  68. data/test/test_exception_handler.rb +56 -0
  69. data/test/test_extensions.rb +127 -0
  70. data/test/test_fetch.rb +50 -0
  71. data/test/test_launcher.rb +85 -0
  72. data/test/test_logging.rb +35 -0
  73. data/test/test_manager.rb +50 -0
  74. data/test/test_middleware.rb +158 -0
  75. data/test/test_processor.rb +201 -0
  76. data/test/test_rails.rb +22 -0
  77. data/test/test_redis_connection.rb +127 -0
  78. data/test/test_retry.rb +326 -0
  79. data/test/test_retry_exhausted.rb +149 -0
  80. data/test/test_scheduled.rb +115 -0
  81. data/test/test_scheduling.rb +50 -0
  82. data/test/test_sidekiq.rb +107 -0
  83. data/test/test_testing.rb +143 -0
  84. data/test/test_testing_fake.rb +357 -0
  85. data/test/test_testing_inline.rb +94 -0
  86. data/test/test_util.rb +13 -0
  87. data/test/test_web.rb +614 -0
  88. data/test/test_web_helpers.rb +54 -0
  89. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  90. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  91. data/web/assets/images/favicon.ico +0 -0
  92. data/web/assets/images/logo.png +0 -0
  93. data/web/assets/images/status-sd8051fd480.png +0 -0
  94. data/web/assets/images/status/active.png +0 -0
  95. data/web/assets/images/status/idle.png +0 -0
  96. data/web/assets/javascripts/application.js +88 -0
  97. data/web/assets/javascripts/dashboard.js +300 -0
  98. data/web/assets/javascripts/locales/README.md +27 -0
  99. data/web/assets/javascripts/locales/jquery.timeago.ar.js +96 -0
  100. data/web/assets/javascripts/locales/jquery.timeago.bg.js +18 -0
  101. data/web/assets/javascripts/locales/jquery.timeago.bs.js +49 -0
  102. data/web/assets/javascripts/locales/jquery.timeago.ca.js +18 -0
  103. data/web/assets/javascripts/locales/jquery.timeago.cs.js +18 -0
  104. data/web/assets/javascripts/locales/jquery.timeago.cy.js +20 -0
  105. data/web/assets/javascripts/locales/jquery.timeago.da.js +18 -0
  106. data/web/assets/javascripts/locales/jquery.timeago.de.js +18 -0
  107. data/web/assets/javascripts/locales/jquery.timeago.el.js +18 -0
  108. data/web/assets/javascripts/locales/jquery.timeago.en-short.js +20 -0
  109. data/web/assets/javascripts/locales/jquery.timeago.en.js +20 -0
  110. data/web/assets/javascripts/locales/jquery.timeago.es.js +18 -0
  111. data/web/assets/javascripts/locales/jquery.timeago.et.js +18 -0
  112. data/web/assets/javascripts/locales/jquery.timeago.fa.js +22 -0
  113. data/web/assets/javascripts/locales/jquery.timeago.fi.js +28 -0
  114. data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +16 -0
  115. data/web/assets/javascripts/locales/jquery.timeago.fr.js +17 -0
  116. data/web/assets/javascripts/locales/jquery.timeago.he.js +18 -0
  117. data/web/assets/javascripts/locales/jquery.timeago.hr.js +49 -0
  118. data/web/assets/javascripts/locales/jquery.timeago.hu.js +18 -0
  119. data/web/assets/javascripts/locales/jquery.timeago.hy.js +18 -0
  120. data/web/assets/javascripts/locales/jquery.timeago.id.js +18 -0
  121. data/web/assets/javascripts/locales/jquery.timeago.it.js +16 -0
  122. data/web/assets/javascripts/locales/jquery.timeago.ja.js +19 -0
  123. data/web/assets/javascripts/locales/jquery.timeago.ko.js +17 -0
  124. data/web/assets/javascripts/locales/jquery.timeago.lt.js +20 -0
  125. data/web/assets/javascripts/locales/jquery.timeago.mk.js +20 -0
  126. data/web/assets/javascripts/locales/jquery.timeago.nl.js +20 -0
  127. data/web/assets/javascripts/locales/jquery.timeago.no.js +18 -0
  128. data/web/assets/javascripts/locales/jquery.timeago.pl.js +31 -0
  129. data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +16 -0
  130. data/web/assets/javascripts/locales/jquery.timeago.pt.js +16 -0
  131. data/web/assets/javascripts/locales/jquery.timeago.ro.js +18 -0
  132. data/web/assets/javascripts/locales/jquery.timeago.rs.js +49 -0
  133. data/web/assets/javascripts/locales/jquery.timeago.ru.js +34 -0
  134. data/web/assets/javascripts/locales/jquery.timeago.sk.js +18 -0
  135. data/web/assets/javascripts/locales/jquery.timeago.sl.js +44 -0
  136. data/web/assets/javascripts/locales/jquery.timeago.sv.js +18 -0
  137. data/web/assets/javascripts/locales/jquery.timeago.th.js +20 -0
  138. data/web/assets/javascripts/locales/jquery.timeago.tr.js +16 -0
  139. data/web/assets/javascripts/locales/jquery.timeago.uk.js +34 -0
  140. data/web/assets/javascripts/locales/jquery.timeago.uz.js +19 -0
  141. data/web/assets/javascripts/locales/jquery.timeago.zh-cn.js +20 -0
  142. data/web/assets/javascripts/locales/jquery.timeago.zh-tw.js +20 -0
  143. data/web/assets/stylesheets/application.css +754 -0
  144. data/web/assets/stylesheets/bootstrap.css +9 -0
  145. data/web/locales/cs.yml +78 -0
  146. data/web/locales/da.yml +68 -0
  147. data/web/locales/de.yml +69 -0
  148. data/web/locales/el.yml +68 -0
  149. data/web/locales/en.yml +79 -0
  150. data/web/locales/es.yml +69 -0
  151. data/web/locales/fr.yml +78 -0
  152. data/web/locales/hi.yml +75 -0
  153. data/web/locales/it.yml +69 -0
  154. data/web/locales/ja.yml +78 -0
  155. data/web/locales/ko.yml +68 -0
  156. data/web/locales/nb.yml +77 -0
  157. data/web/locales/nl.yml +68 -0
  158. data/web/locales/pl.yml +59 -0
  159. data/web/locales/pt-br.yml +68 -0
  160. data/web/locales/pt.yml +67 -0
  161. data/web/locales/ru.yml +78 -0
  162. data/web/locales/sv.yml +68 -0
  163. data/web/locales/ta.yml +75 -0
  164. data/web/locales/uk.yml +76 -0
  165. data/web/locales/zh-cn.yml +68 -0
  166. data/web/locales/zh-tw.yml +68 -0
  167. data/web/views/_footer.erb +17 -0
  168. data/web/views/_job_info.erb +88 -0
  169. data/web/views/_nav.erb +66 -0
  170. data/web/views/_paging.erb +23 -0
  171. data/web/views/_poll_js.erb +5 -0
  172. data/web/views/_poll_link.erb +7 -0
  173. data/web/views/_status.erb +4 -0
  174. data/web/views/_summary.erb +40 -0
  175. data/web/views/busy.erb +94 -0
  176. data/web/views/dashboard.erb +75 -0
  177. data/web/views/dead.erb +34 -0
  178. data/web/views/layout.erb +32 -0
  179. data/web/views/morgue.erb +71 -0
  180. data/web/views/queue.erb +45 -0
  181. data/web/views/queues.erb +28 -0
  182. data/web/views/retries.erb +74 -0
  183. data/web/views/retry.erb +34 -0
  184. data/web/views/scheduled.erb +54 -0
  185. data/web/views/scheduled_job_info.erb +8 -0
  186. metadata +408 -0
data/README.md ADDED
@@ -0,0 +1,8 @@
1
+ SR-Sidekiq
2
+ ==============
3
+
4
+ SR-Sidekiq is merely a fork of Sidekiq (v4.1.2). All ruby code is the same with the exception that one or more classes have been modified to be more restrictive of what arguments can be passed in.
5
+
6
+ Specifically, workers can only receive numerical arguments to their `perform` methods.
7
+
8
+ All credits are directed to [Sidekiq](http://sidekiq.org/). This fantastic gem is authored by: Mike Perham, [@mperham](https://twitter.com/mperham) / [@sidekiq](https://twitter.com/sidekiq), [http://www.mikeperham.com](http://www.mikeperham.com) / [http://www.contribsys.com](http://www.contribsys.com)
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ Rake::TestTask.new(:test) do |test|
4
+ #SO MUCH NOISE
5
+ #test.warning = true
6
+ test.pattern = 'test/**/test_*.rb'
7
+ end
8
+
9
+ task :default => :test
data/bin/sidekiq ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Quiet some warnings we see when running in warning mode:
4
+ # RUBYOPT=-w bundle exec sidekiq
5
+ $TESTING = false
6
+
7
+ require_relative '../lib/sidekiq/cli'
8
+
9
+ begin
10
+ cli = Sidekiq::CLI.instance
11
+ cli.parse
12
+ cli.run
13
+ rescue => e
14
+ raise e if $DEBUG
15
+ STDERR.puts e.message
16
+ STDERR.puts e.backtrace.join("\n")
17
+ exit 1
18
+ end
data/bin/sidekiqctl ADDED
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fileutils'
4
+
5
+ class Sidekiqctl
6
+ DEFAULT_KILL_TIMEOUT = 10
7
+
8
+ attr_reader :stage, :pidfile, :kill_timeout
9
+
10
+ def self.print_usage
11
+ puts "#{File.basename($0)} - stop a Sidekiq process from the command line."
12
+ puts
13
+ puts "Usage: #{File.basename($0)} <command> <pidfile> <kill_timeout>"
14
+ puts " where <command> is either 'quiet' or 'stop'"
15
+ puts " <pidfile> is path to a pidfile"
16
+ puts " <kill_timeout> is number of seconds to wait until Sidekiq exits"
17
+ puts " (default: #{Sidekiqctl::DEFAULT_KILL_TIMEOUT}), after which Sidekiq will be KILL'd"
18
+ puts
19
+ puts "Be sure to set the kill_timeout LONGER than Sidekiq's -t timeout. If you want"
20
+ puts "to wait 60 seconds for jobs to finish, use `sidekiq -t 60` and `sidekiqctl stop"
21
+ puts " path_to_pidfile 61`"
22
+ puts
23
+ end
24
+
25
+ def initialize(stage, pidfile, timeout)
26
+ @stage = stage
27
+ @pidfile = pidfile
28
+ @kill_timeout = timeout
29
+
30
+ done('No pidfile given', :error) if !pidfile
31
+ done("Pidfile #{pidfile} does not exist", :warn) if !File.exist?(pidfile)
32
+ done('Invalid pidfile content', :error) if pid == 0
33
+
34
+ fetch_process
35
+
36
+ begin
37
+ send(stage)
38
+ rescue NoMethodError
39
+ done "Invalid command: #{stage}", :error
40
+ end
41
+ end
42
+
43
+ def fetch_process
44
+ Process.kill(0, pid)
45
+ rescue Errno::ESRCH
46
+ done "Process doesn't exist", :error
47
+ # We were not allowed to send a signal, but the process must have existed
48
+ # when Process.kill() was called.
49
+ rescue Errno::EPERM
50
+ return pid
51
+ end
52
+
53
+ def done(msg, error = nil)
54
+ puts msg
55
+ exit(exit_signal(error))
56
+ end
57
+
58
+ def exit_signal(error)
59
+ (error == :error) ? 1 : 0
60
+ end
61
+
62
+ def pid
63
+ @pid ||= File.read(pidfile).to_i
64
+ end
65
+
66
+ def quiet
67
+ `kill -USR1 #{pid}`
68
+ end
69
+
70
+ def stop
71
+ `kill -TERM #{pid}`
72
+ kill_timeout.times do
73
+ begin
74
+ Process.kill(0, pid)
75
+ rescue Errno::ESRCH
76
+ FileUtils.rm_f pidfile
77
+ done 'Sidekiq shut down gracefully.'
78
+ rescue Errno::EPERM
79
+ done 'Not permitted to shut down Sidekiq.'
80
+ end
81
+ sleep 1
82
+ end
83
+ `kill -9 #{pid}`
84
+ FileUtils.rm_f pidfile
85
+ done 'Sidekiq shut down forcefully.'
86
+ end
87
+ alias_method :shutdown, :stop
88
+ end
89
+
90
+ if ARGV.length < 2
91
+ Sidekiqctl.print_usage
92
+ else
93
+ stage = ARGV[0]
94
+ pidfile = ARGV[1]
95
+ timeout = ARGV[2].to_i
96
+ timeout = Sidekiqctl::DEFAULT_KILL_TIMEOUT if timeout == 0
97
+
98
+ Sidekiqctl.new(stage, pidfile, timeout)
99
+ end
data/bin/sidekiqload ADDED
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Quiet some warnings we see when running in warning mode:
4
+ # RUBYOPT=-w bundle exec sidekiq
5
+ $TESTING = false
6
+
7
+ #require 'ruby-prof'
8
+ Bundler.require(:default)
9
+
10
+ require_relative '../lib/sidekiq/cli'
11
+ require_relative '../lib/sidekiq/launcher'
12
+
13
+ include Sidekiq::Util
14
+
15
+ # brew tap shopify/shopify
16
+ # brew install toxiproxy
17
+ # gem install toxiproxy
18
+ require 'toxiproxy'
19
+ # simulate a non-localhost network for realer-world conditions.
20
+ # adding 1ms of network latency has an ENORMOUS impact on benchmarks
21
+ Toxiproxy.populate([{
22
+ "name": "redis",
23
+ "listen": "127.0.0.1:6380",
24
+ "upstream": "127.0.0.1:6379"
25
+ }])
26
+
27
+
28
+ Sidekiq.configure_server do |config|
29
+ #config.options[:concurrency] = 1
30
+ config.redis = { driver: :hiredis, db: 13, port: 6380 }
31
+ config.options[:queues] << 'default'
32
+ config.logger.level = Logger::ERROR
33
+ config.average_scheduled_poll_interval = 2
34
+ config.reliable! if defined?(Sidekiq::Pro)
35
+ end
36
+
37
+ class LoadWorker
38
+ include Sidekiq::Worker
39
+ sidekiq_options retry: 1
40
+ sidekiq_retry_in do |x|
41
+ 1
42
+ end
43
+
44
+ def perform(idx)
45
+ #raise idx.to_s if idx % 100 == 1
46
+ end
47
+ end
48
+
49
+ # brew tap shopify/shopify
50
+ # brew install toxiproxy
51
+ # gem install toxiproxy
52
+ require 'toxiproxy'
53
+ # simulate a non-localhost network for realer-world conditions.
54
+ # adding 1ms of network latency has an ENORMOUS impact on benchmarks
55
+ Toxiproxy.populate([{
56
+ "name": "redis",
57
+ "listen": "127.0.0.1:6380",
58
+ "upstream": "127.0.0.1:6379"
59
+ }])
60
+
61
+ self_read, self_write = IO.pipe
62
+ %w(INT TERM USR1 USR2 TTIN).each do |sig|
63
+ begin
64
+ trap sig do
65
+ self_write.puts(sig)
66
+ end
67
+ rescue ArgumentError
68
+ puts "Signal #{sig} not supported"
69
+ end
70
+ end
71
+
72
+ Sidekiq.redis {|c| c.flushdb}
73
+ def handle_signal(launcher, sig)
74
+ Sidekiq.logger.debug "Got #{sig} signal"
75
+ case sig
76
+ when 'INT'
77
+ # Handle Ctrl-C in JRuby like MRI
78
+ # http://jira.codehaus.org/browse/JRUBY-4637
79
+ raise Interrupt
80
+ when 'TERM'
81
+ # Heroku sends TERM and then waits 10 seconds for process to exit.
82
+ raise Interrupt
83
+ when 'USR1'
84
+ Sidekiq.logger.info "Received USR1, no longer accepting new work"
85
+ launcher.quiet
86
+ when 'USR2'
87
+ if Sidekiq.options[:logfile]
88
+ Sidekiq.logger.info "Received USR2, reopening log file"
89
+ Sidekiq::Logging.reopen_logs
90
+ end
91
+ when 'TTIN'
92
+ Thread.list.each do |thread|
93
+ Sidekiq.logger.warn "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
94
+ if thread.backtrace
95
+ Sidekiq.logger.warn thread.backtrace.join("\n")
96
+ else
97
+ Sidekiq.logger.warn "<no backtrace available>"
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ def Process.rss
104
+ `ps -o rss= -p #{Process.pid}`.chomp.to_i
105
+ end
106
+
107
+ iter = 10
108
+ count = 10_000
109
+
110
+ iter.times do
111
+ arr = Array.new(count) do
112
+ []
113
+ end
114
+ count.times do |idx|
115
+ arr[idx][0] = idx
116
+ end
117
+ Sidekiq::Client.push_bulk('class' => LoadWorker, 'args' => arr)
118
+ end
119
+ Sidekiq.logger.error "Created #{count*iter} jobs"
120
+
121
+ Monitoring = Thread.new do
122
+ watchdog("monitor thread") do
123
+ while true
124
+ sleep 2
125
+ qsize, retries = Sidekiq.redis do |conn|
126
+ conn.pipelined do
127
+ conn.llen "queue:default"
128
+ conn.zcard "retry"
129
+ end
130
+ end.map(&:to_i)
131
+ total = qsize + retries
132
+ #GC.start
133
+ Sidekiq.logger.error("RSS: #{Process.rss} Pending: #{total}")
134
+ if total == 0
135
+ Sidekiq.logger.error("Done")
136
+ exit(0)
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ begin
143
+ #RubyProf::exclude_threads = [ Monitoring ]
144
+ #RubyProf.start
145
+ fire_event(:startup)
146
+ Sidekiq.logger.error "Simulating 1ms of latency between Sidekiq and redis"
147
+ Toxiproxy[:redis].downstream(:latency, latency: 1).apply do
148
+ launcher = Sidekiq::Launcher.new(Sidekiq.options)
149
+ launcher.run
150
+
151
+ while readable_io = IO.select([self_read])
152
+ signal = readable_io.first[0].gets.strip
153
+ handle_signal(launcher, signal)
154
+ end
155
+ end
156
+ rescue SystemExit => e
157
+ #Sidekiq.logger.error("Profiling...")
158
+ #result = RubyProf.stop
159
+ #printer = RubyProf::GraphHtmlPrinter.new(result)
160
+ #printer.print(File.new("output.html", "w"), :min_percent => 1)
161
+ # normal
162
+ rescue => e
163
+ raise e if $DEBUG
164
+ STDERR.puts e.message
165
+ STDERR.puts e.backtrace.join("\n")
166
+ exit 1
167
+ end
@@ -0,0 +1,50 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This Code of Conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting the project maintainer at mperham AT gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+
45
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
46
+ version 1.3.0, available at
47
+ [http://contributor-covenant.org/version/1/3/0/][version]
48
+
49
+ [homepage]: http://contributor-covenant.org
50
+ [version]: http://contributor-covenant.org/version/1/3/0/
@@ -0,0 +1,9 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Worker
3
+ include Sidekiq::Worker
4
+
5
+ def perform(*args)
6
+ # Do something
7
+ end
8
+ end
9
+ <% end -%>
@@ -0,0 +1,6 @@
1
+ require 'rails_helper'
2
+ <% module_namespacing do -%>
3
+ RSpec.describe <%= class_name %>Worker, type: :worker do
4
+ pending "add some examples to (or delete) #{__FILE__}"
5
+ end
6
+ <% end -%>
@@ -0,0 +1,8 @@
1
+ require_relative 'test_helper'
2
+ <% module_namespacing do -%>
3
+ class <%= class_name %>WorkerTest < <% if defined? Minitest::Test %>Minitest::Test<% else %>MiniTest::Unit::TestCase<% end %>
4
+ def test_example
5
+ skip "add some examples to (or delete) #{__FILE__}"
6
+ end
7
+ end
8
+ <% end -%>
@@ -0,0 +1,49 @@
1
+ require 'rails/generators/named_base'
2
+
3
+ module Sidekiq
4
+ module Generators # :nodoc:
5
+ class WorkerGenerator < ::Rails::Generators::NamedBase # :nodoc:
6
+ desc 'This generator creates a Sidekiq Worker in app/workers and a corresponding test'
7
+
8
+ check_class_collision suffix: 'Worker'
9
+
10
+ def self.default_generator_root
11
+ File.dirname(__FILE__)
12
+ end
13
+
14
+ def create_worker_file
15
+ template 'worker.rb.erb', File.join('app/workers', class_path, "#{file_name}_worker.rb")
16
+ end
17
+
18
+ def create_test_file
19
+ if defined?(RSpec)
20
+ create_worker_spec
21
+ else
22
+ create_worker_test
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def create_worker_spec
29
+ template_file = File.join(
30
+ 'spec/workers',
31
+ class_path,
32
+ "#{file_name}_worker_spec.rb"
33
+ )
34
+ template 'worker_spec.rb.erb', template_file
35
+ end
36
+
37
+ def create_worker_test
38
+ template_file = File.join(
39
+ 'test/workers',
40
+ class_path,
41
+ "#{file_name}_worker_test.rb"
42
+ )
43
+ template 'worker_test.rb.erb', template_file
44
+ end
45
+
46
+
47
+ end
48
+ end
49
+ end
data/lib/sidekiq.rb ADDED
@@ -0,0 +1,237 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+ require 'sidekiq/version'
4
+ fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.0.0." if RUBY_PLATFORM != 'java' && RUBY_VERSION < '2.0.0'
5
+
6
+ require 'sidekiq/logging'
7
+ require 'sidekiq/client'
8
+ require 'sidekiq/worker'
9
+ require 'sidekiq/redis_connection'
10
+
11
+ require 'json'
12
+
13
+ module Sidekiq
14
+ NAME = 'Sidekiq'
15
+ LICENSE = 'See LICENSE and the LGPL-3.0 for licensing details.'
16
+
17
+ DEFAULTS = {
18
+ queues: [],
19
+ labels: [],
20
+ concurrency: 25,
21
+ require: '.',
22
+ environment: nil,
23
+ timeout: 8,
24
+ poll_interval_average: nil,
25
+ average_scheduled_poll_interval: 15,
26
+ error_handlers: [],
27
+ lifecycle_events: {
28
+ startup: [],
29
+ quiet: [],
30
+ shutdown: [],
31
+ },
32
+ dead_max_jobs: 10_000,
33
+ dead_timeout_in_seconds: 180 * 24 * 60 * 60 # 6 months
34
+ }
35
+
36
+ DEFAULT_WORKER_OPTIONS = {
37
+ 'retry' => true,
38
+ 'queue' => 'default'
39
+ }
40
+
41
+ FAKE_INFO = {
42
+ "redis_version" => "9.9.9",
43
+ "uptime_in_days" => "9999",
44
+ "connected_clients" => "9999",
45
+ "used_memory_human" => "9P",
46
+ "used_memory_peak_human" => "9P"
47
+ }.freeze
48
+
49
+ def self.❨╯°□°❩╯︵┻━┻
50
+ puts "Calm down, yo."
51
+ end
52
+
53
+ def self.options
54
+ @options ||= DEFAULTS.dup
55
+ end
56
+ def self.options=(opts)
57
+ @options = opts
58
+ end
59
+
60
+ ##
61
+ # Configuration for Sidekiq server, use like:
62
+ #
63
+ # Sidekiq.configure_server do |config|
64
+ # config.redis = { :namespace => 'myapp', :size => 25, :url => 'redis://myhost:8877/0' }
65
+ # config.server_middleware do |chain|
66
+ # chain.add MyServerHook
67
+ # end
68
+ # end
69
+ def self.configure_server
70
+ yield self if server?
71
+ end
72
+
73
+ ##
74
+ # Configuration for Sidekiq client, use like:
75
+ #
76
+ # Sidekiq.configure_client do |config|
77
+ # config.redis = { :namespace => 'myapp', :size => 1, :url => 'redis://myhost:8877/0' }
78
+ # end
79
+ def self.configure_client
80
+ yield self unless server?
81
+ end
82
+
83
+ def self.server?
84
+ defined?(Sidekiq::CLI)
85
+ end
86
+
87
+ def self.redis
88
+ raise ArgumentError, "requires a block" unless block_given?
89
+ redis_pool.with do |conn|
90
+ retryable = true
91
+ begin
92
+ yield conn
93
+ rescue Redis::CommandError => ex
94
+ #2550 Failover can cause the server to become a slave, need
95
+ # to disconnect and reopen the socket to get back to the master.
96
+ (conn.disconnect!; retryable = false; retry) if retryable && ex.message =~ /READONLY/
97
+ raise
98
+ end
99
+ end
100
+ end
101
+
102
+ def self.redis_info
103
+ redis do |conn|
104
+ begin
105
+ # admin commands can't go through redis-namespace starting
106
+ # in redis-namespace 2.0
107
+ if conn.respond_to?(:namespace)
108
+ conn.redis.info
109
+ else
110
+ conn.info
111
+ end
112
+ rescue Redis::CommandError => ex
113
+ #2850 return fake version when INFO command has (probably) been renamed
114
+ raise unless ex.message =~ /unknown command/
115
+ FAKE_INFO
116
+ end
117
+ end
118
+ end
119
+
120
+ def self.redis_pool
121
+ @redis ||= Sidekiq::RedisConnection.create
122
+ end
123
+
124
+ def self.redis=(hash)
125
+ @redis = if hash.is_a?(ConnectionPool)
126
+ hash
127
+ else
128
+ Sidekiq::RedisConnection.create(hash)
129
+ end
130
+ end
131
+
132
+ def self.client_middleware
133
+ @client_chain ||= Middleware::Chain.new
134
+ yield @client_chain if block_given?
135
+ @client_chain
136
+ end
137
+
138
+ def self.server_middleware
139
+ @server_chain ||= default_server_middleware
140
+ yield @server_chain if block_given?
141
+ @server_chain
142
+ end
143
+
144
+ def self.default_server_middleware
145
+ require 'sidekiq/middleware/server/retry_jobs'
146
+ require 'sidekiq/middleware/server/logging'
147
+
148
+ Middleware::Chain.new do |m|
149
+ m.add Middleware::Server::Logging
150
+ m.add Middleware::Server::RetryJobs
151
+ if defined?(::ActiveRecord::Base)
152
+ require 'sidekiq/middleware/server/active_record'
153
+ m.add Sidekiq::Middleware::Server::ActiveRecord
154
+ end
155
+ end
156
+ end
157
+
158
+ def self.default_worker_options=(hash)
159
+ @default_worker_options = default_worker_options.merge(hash.stringify_keys)
160
+ end
161
+ def self.default_worker_options
162
+ defined?(@default_worker_options) ? @default_worker_options : DEFAULT_WORKER_OPTIONS
163
+ end
164
+
165
+ # Sidekiq.configure_server do |config|
166
+ # config.default_retries_exhausted = -> (job, ex) do
167
+ # end
168
+ # end
169
+ def self.default_retries_exhausted=(prok)
170
+ @default_retries_exhausted = prok
171
+ end
172
+ def self.default_retries_exhausted
173
+ @default_retries_exhausted
174
+ end
175
+
176
+ def self.load_json(string)
177
+ JSON.parse(string)
178
+ end
179
+ def self.dump_json(object)
180
+ JSON.generate(object)
181
+ end
182
+
183
+ def self.logger
184
+ Sidekiq::Logging.logger
185
+ end
186
+ def self.logger=(log)
187
+ Sidekiq::Logging.logger = log
188
+ end
189
+
190
+ # How frequently Redis should be checked by a random Sidekiq process for
191
+ # scheduled and retriable jobs. Each individual process will take turns by
192
+ # waiting some multiple of this value.
193
+ #
194
+ # See sidekiq/scheduled.rb for an in-depth explanation of this value
195
+ def self.average_scheduled_poll_interval=(interval)
196
+ self.options[:average_scheduled_poll_interval] = interval
197
+ end
198
+
199
+ # Register a proc to handle any error which occurs within the Sidekiq process.
200
+ #
201
+ # Sidekiq.configure_server do |config|
202
+ # config.error_handlers << proc {|ex,ctx_hash| MyErrorService.notify(ex, ctx_hash) }
203
+ # end
204
+ #
205
+ # The default error handler logs errors to Sidekiq.logger.
206
+ def self.error_handlers
207
+ self.options[:error_handlers]
208
+ end
209
+
210
+ # Register a block to run at a point in the Sidekiq lifecycle.
211
+ # :startup, :quiet or :shutdown are valid events.
212
+ #
213
+ # Sidekiq.configure_server do |config|
214
+ # config.on(:shutdown) do
215
+ # puts "Goodbye cruel world!"
216
+ # end
217
+ # end
218
+ def self.on(event, &block)
219
+ raise ArgumentError, "Symbols only please: #{event}" unless event.is_a?(Symbol)
220
+ raise ArgumentError, "Invalid event name: #{event}" unless options[:lifecycle_events].key?(event)
221
+ options[:lifecycle_events][event] << block
222
+ end
223
+
224
+ # We are shutting down Sidekiq but what about workers that
225
+ # are working on some long job? This error is
226
+ # raised in workers that have not finished within the hard
227
+ # timeout limit. This is needed to rollback db transactions,
228
+ # otherwise Ruby's Thread#kill will commit. See #377.
229
+ # DO NOT RESCUE THIS ERROR IN YOUR WORKERS
230
+ class Shutdown < Interrupt; end
231
+
232
+ end
233
+
234
+ require 'sidekiq/extensions/class_methods'
235
+ require 'sidekiq/extensions/action_mailer'
236
+ require 'sidekiq/extensions/active_record'
237
+ require 'sidekiq/rails' if defined?(::Rails::Engine)