sidekiq 0.10.0 → 7.2.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 (234) hide show
  1. checksums.yaml +7 -0
  2. data/Changes.md +2082 -0
  3. data/LICENSE.txt +9 -0
  4. data/README.md +73 -27
  5. data/bin/sidekiq +25 -9
  6. data/bin/sidekiqload +247 -0
  7. data/bin/sidekiqmon +11 -0
  8. data/lib/generators/sidekiq/job_generator.rb +57 -0
  9. data/lib/generators/sidekiq/templates/job.rb.erb +9 -0
  10. data/lib/generators/sidekiq/templates/job_spec.rb.erb +6 -0
  11. data/lib/generators/sidekiq/templates/job_test.rb.erb +8 -0
  12. data/lib/sidekiq/api.rb +1145 -0
  13. data/lib/sidekiq/capsule.rb +127 -0
  14. data/lib/sidekiq/cli.rb +348 -109
  15. data/lib/sidekiq/client.rb +241 -41
  16. data/lib/sidekiq/component.rb +68 -0
  17. data/lib/sidekiq/config.rb +287 -0
  18. data/lib/sidekiq/deploy.rb +62 -0
  19. data/lib/sidekiq/embedded.rb +61 -0
  20. data/lib/sidekiq/fetch.rb +88 -0
  21. data/lib/sidekiq/job.rb +374 -0
  22. data/lib/sidekiq/job_logger.rb +51 -0
  23. data/lib/sidekiq/job_retry.rb +301 -0
  24. data/lib/sidekiq/job_util.rb +107 -0
  25. data/lib/sidekiq/launcher.rb +271 -0
  26. data/lib/sidekiq/logger.rb +131 -0
  27. data/lib/sidekiq/manager.rb +96 -103
  28. data/lib/sidekiq/metrics/query.rb +155 -0
  29. data/lib/sidekiq/metrics/shared.rb +95 -0
  30. data/lib/sidekiq/metrics/tracking.rb +136 -0
  31. data/lib/sidekiq/middleware/chain.rb +149 -38
  32. data/lib/sidekiq/middleware/current_attributes.rb +95 -0
  33. data/lib/sidekiq/middleware/i18n.rb +42 -0
  34. data/lib/sidekiq/middleware/modules.rb +21 -0
  35. data/lib/sidekiq/monitor.rb +146 -0
  36. data/lib/sidekiq/paginator.rb +55 -0
  37. data/lib/sidekiq/processor.rb +246 -61
  38. data/lib/sidekiq/rails.rb +60 -13
  39. data/lib/sidekiq/redis_client_adapter.rb +111 -0
  40. data/lib/sidekiq/redis_connection.rb +68 -15
  41. data/lib/sidekiq/ring_buffer.rb +29 -0
  42. data/lib/sidekiq/scheduled.rb +236 -0
  43. data/lib/sidekiq/sd_notify.rb +149 -0
  44. data/lib/sidekiq/systemd.rb +24 -0
  45. data/lib/sidekiq/testing/inline.rb +30 -0
  46. data/lib/sidekiq/testing.rb +310 -10
  47. data/lib/sidekiq/transaction_aware_client.rb +44 -0
  48. data/lib/sidekiq/version.rb +4 -1
  49. data/lib/sidekiq/web/action.rb +93 -0
  50. data/lib/sidekiq/web/application.rb +463 -0
  51. data/lib/sidekiq/web/csrf_protection.rb +180 -0
  52. data/lib/sidekiq/web/helpers.rb +364 -0
  53. data/lib/sidekiq/web/router.rb +104 -0
  54. data/lib/sidekiq/web.rb +143 -74
  55. data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
  56. data/lib/sidekiq.rb +120 -73
  57. data/sidekiq.gemspec +26 -23
  58. data/web/assets/images/apple-touch-icon.png +0 -0
  59. data/web/assets/images/favicon.ico +0 -0
  60. data/web/assets/images/logo.png +0 -0
  61. data/web/assets/images/status.png +0 -0
  62. data/web/assets/javascripts/application.js +177 -3
  63. data/web/assets/javascripts/base-charts.js +106 -0
  64. data/web/assets/javascripts/chart.min.js +13 -0
  65. data/web/assets/javascripts/chartjs-plugin-annotation.min.js +7 -0
  66. data/web/assets/javascripts/dashboard-charts.js +182 -0
  67. data/web/assets/javascripts/dashboard.js +57 -0
  68. data/web/assets/javascripts/metrics.js +298 -0
  69. data/web/assets/stylesheets/application-dark.css +147 -0
  70. data/web/assets/stylesheets/application-rtl.css +153 -0
  71. data/web/assets/stylesheets/application.css +729 -7
  72. data/web/assets/stylesheets/bootstrap-rtl.min.css +9 -0
  73. data/web/assets/stylesheets/bootstrap.css +5 -0
  74. data/web/locales/ar.yml +87 -0
  75. data/web/locales/cs.yml +78 -0
  76. data/web/locales/da.yml +75 -0
  77. data/web/locales/de.yml +81 -0
  78. data/web/locales/el.yml +87 -0
  79. data/web/locales/en.yml +101 -0
  80. data/web/locales/es.yml +86 -0
  81. data/web/locales/fa.yml +80 -0
  82. data/web/locales/fr.yml +99 -0
  83. data/web/locales/gd.yml +99 -0
  84. data/web/locales/he.yml +80 -0
  85. data/web/locales/hi.yml +75 -0
  86. data/web/locales/it.yml +69 -0
  87. data/web/locales/ja.yml +91 -0
  88. data/web/locales/ko.yml +68 -0
  89. data/web/locales/lt.yml +83 -0
  90. data/web/locales/nb.yml +77 -0
  91. data/web/locales/nl.yml +68 -0
  92. data/web/locales/pl.yml +59 -0
  93. data/web/locales/pt-br.yml +96 -0
  94. data/web/locales/pt.yml +67 -0
  95. data/web/locales/ru.yml +83 -0
  96. data/web/locales/sv.yml +68 -0
  97. data/web/locales/ta.yml +75 -0
  98. data/web/locales/uk.yml +77 -0
  99. data/web/locales/ur.yml +80 -0
  100. data/web/locales/vi.yml +83 -0
  101. data/web/locales/zh-cn.yml +95 -0
  102. data/web/locales/zh-tw.yml +102 -0
  103. data/web/views/_footer.erb +23 -0
  104. data/web/views/_job_info.erb +105 -0
  105. data/web/views/_metrics_period_select.erb +12 -0
  106. data/web/views/_nav.erb +52 -0
  107. data/web/views/_paging.erb +25 -0
  108. data/web/views/_poll_link.erb +4 -0
  109. data/web/views/_status.erb +4 -0
  110. data/web/views/_summary.erb +40 -0
  111. data/web/views/busy.erb +148 -0
  112. data/web/views/dashboard.erb +105 -0
  113. data/web/views/dead.erb +34 -0
  114. data/web/views/filtering.erb +7 -0
  115. data/web/views/layout.erb +42 -0
  116. data/web/views/metrics.erb +91 -0
  117. data/web/views/metrics_for_job.erb +59 -0
  118. data/web/views/morgue.erb +74 -0
  119. data/web/views/queue.erb +55 -0
  120. data/web/views/queues.erb +44 -0
  121. data/web/views/retries.erb +79 -0
  122. data/web/views/retry.erb +34 -0
  123. data/web/views/scheduled.erb +56 -0
  124. data/web/views/scheduled_job_info.erb +8 -0
  125. metadata +159 -237
  126. data/.gitignore +0 -6
  127. data/.rvmrc +0 -4
  128. data/COMM-LICENSE +0 -75
  129. data/Gemfile +0 -10
  130. data/LICENSE +0 -22
  131. data/Rakefile +0 -9
  132. data/TODO.md +0 -1
  133. data/bin/client +0 -7
  134. data/bin/sidekiqctl +0 -43
  135. data/config.ru +0 -8
  136. data/examples/chef/cookbooks/sidekiq/README.rdoc +0 -11
  137. data/examples/chef/cookbooks/sidekiq/recipes/default.rb +0 -55
  138. data/examples/chef/cookbooks/sidekiq/templates/default/monitrc.conf.erb +0 -8
  139. data/examples/chef/cookbooks/sidekiq/templates/default/sidekiq.erb +0 -219
  140. data/examples/chef/cookbooks/sidekiq/templates/default/sidekiq.yml.erb +0 -22
  141. data/examples/config.yml +0 -9
  142. data/examples/monitrc.conf +0 -6
  143. data/examples/por.rb +0 -27
  144. data/examples/scheduling.rb +0 -37
  145. data/examples/sinkiq.rb +0 -57
  146. data/examples/web-ui.png +0 -0
  147. data/lib/sidekiq/capistrano.rb +0 -32
  148. data/lib/sidekiq/extensions/action_mailer.rb +0 -26
  149. data/lib/sidekiq/extensions/active_record.rb +0 -27
  150. data/lib/sidekiq/extensions/generic_proxy.rb +0 -21
  151. data/lib/sidekiq/middleware/client/unique_jobs.rb +0 -32
  152. data/lib/sidekiq/middleware/server/active_record.rb +0 -13
  153. data/lib/sidekiq/middleware/server/exception_handler.rb +0 -38
  154. data/lib/sidekiq/middleware/server/failure_jobs.rb +0 -24
  155. data/lib/sidekiq/middleware/server/logging.rb +0 -27
  156. data/lib/sidekiq/middleware/server/retry_jobs.rb +0 -59
  157. data/lib/sidekiq/middleware/server/unique_jobs.rb +0 -15
  158. data/lib/sidekiq/retry.rb +0 -57
  159. data/lib/sidekiq/util.rb +0 -61
  160. data/lib/sidekiq/worker.rb +0 -37
  161. data/myapp/.gitignore +0 -15
  162. data/myapp/Capfile +0 -5
  163. data/myapp/Gemfile +0 -19
  164. data/myapp/Gemfile.lock +0 -143
  165. data/myapp/Rakefile +0 -7
  166. data/myapp/app/controllers/application_controller.rb +0 -3
  167. data/myapp/app/controllers/work_controller.rb +0 -38
  168. data/myapp/app/helpers/application_helper.rb +0 -2
  169. data/myapp/app/mailers/.gitkeep +0 -0
  170. data/myapp/app/mailers/user_mailer.rb +0 -9
  171. data/myapp/app/models/.gitkeep +0 -0
  172. data/myapp/app/models/post.rb +0 -5
  173. data/myapp/app/views/layouts/application.html.erb +0 -14
  174. data/myapp/app/views/user_mailer/greetings.html.erb +0 -3
  175. data/myapp/app/views/work/index.html.erb +0 -1
  176. data/myapp/app/workers/hard_worker.rb +0 -9
  177. data/myapp/config/application.rb +0 -59
  178. data/myapp/config/boot.rb +0 -6
  179. data/myapp/config/database.yml +0 -25
  180. data/myapp/config/deploy.rb +0 -15
  181. data/myapp/config/environment.rb +0 -5
  182. data/myapp/config/environments/development.rb +0 -38
  183. data/myapp/config/environments/production.rb +0 -67
  184. data/myapp/config/environments/test.rb +0 -37
  185. data/myapp/config/initializers/backtrace_silencers.rb +0 -7
  186. data/myapp/config/initializers/inflections.rb +0 -15
  187. data/myapp/config/initializers/mime_types.rb +0 -5
  188. data/myapp/config/initializers/secret_token.rb +0 -7
  189. data/myapp/config/initializers/session_store.rb +0 -8
  190. data/myapp/config/initializers/sidekiq.rb +0 -6
  191. data/myapp/config/initializers/wrap_parameters.rb +0 -14
  192. data/myapp/config/locales/en.yml +0 -5
  193. data/myapp/config/routes.rb +0 -10
  194. data/myapp/config.ru +0 -4
  195. data/myapp/db/migrate/20120123214055_create_posts.rb +0 -10
  196. data/myapp/db/seeds.rb +0 -7
  197. data/myapp/lib/assets/.gitkeep +0 -0
  198. data/myapp/lib/tasks/.gitkeep +0 -0
  199. data/myapp/log/.gitkeep +0 -0
  200. data/myapp/script/rails +0 -6
  201. data/test/config.yml +0 -9
  202. data/test/fake_env.rb +0 -0
  203. data/test/helper.rb +0 -15
  204. data/test/test_cli.rb +0 -168
  205. data/test/test_client.rb +0 -105
  206. data/test/test_extensions.rb +0 -68
  207. data/test/test_manager.rb +0 -43
  208. data/test/test_middleware.rb +0 -92
  209. data/test/test_processor.rb +0 -32
  210. data/test/test_retry.rb +0 -83
  211. data/test/test_stats.rb +0 -78
  212. data/test/test_testing.rb +0 -65
  213. data/test/test_web.rb +0 -61
  214. data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
  215. data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
  216. data/web/assets/javascripts/vendor/bootstrap/bootstrap-alert.js +0 -91
  217. data/web/assets/javascripts/vendor/bootstrap/bootstrap-button.js +0 -98
  218. data/web/assets/javascripts/vendor/bootstrap/bootstrap-carousel.js +0 -154
  219. data/web/assets/javascripts/vendor/bootstrap/bootstrap-collapse.js +0 -136
  220. data/web/assets/javascripts/vendor/bootstrap/bootstrap-dropdown.js +0 -92
  221. data/web/assets/javascripts/vendor/bootstrap/bootstrap-modal.js +0 -210
  222. data/web/assets/javascripts/vendor/bootstrap/bootstrap-popover.js +0 -95
  223. data/web/assets/javascripts/vendor/bootstrap/bootstrap-scrollspy.js +0 -125
  224. data/web/assets/javascripts/vendor/bootstrap/bootstrap-tab.js +0 -130
  225. data/web/assets/javascripts/vendor/bootstrap/bootstrap-tooltip.js +0 -270
  226. data/web/assets/javascripts/vendor/bootstrap/bootstrap-transition.js +0 -51
  227. data/web/assets/javascripts/vendor/bootstrap/bootstrap-typeahead.js +0 -271
  228. data/web/assets/javascripts/vendor/bootstrap.js +0 -12
  229. data/web/assets/javascripts/vendor/jquery.js +0 -9266
  230. data/web/assets/stylesheets/vendor/bootstrap-responsive.css +0 -567
  231. data/web/assets/stylesheets/vendor/bootstrap.css +0 -3365
  232. data/web/views/index.slim +0 -62
  233. data/web/views/layout.slim +0 -24
  234. data/web/views/queue.slim +0 -11
data/LICENSE.txt ADDED
@@ -0,0 +1,9 @@
1
+ Copyright (c) Contributed Systems LLC
2
+
3
+ Sidekiq is an Open Source project licensed under the terms of
4
+ the LGPLv3 license. Please see <http://www.gnu.org/licenses/lgpl-3.0.html>
5
+ for license text.
6
+
7
+ Sidekiq Pro and Sidekiq Enterprise have a commercial-friendly license.
8
+ You can find the commercial license in COMM-LICENSE.txt.
9
+ Please see https://sidekiq.org for purchasing options.
data/README.md CHANGED
@@ -1,60 +1,106 @@
1
1
  Sidekiq
2
2
  ==============
3
3
 
4
- Simple, efficient message processing for Ruby.
4
+ [![Gem Version](https://badge.fury.io/rb/sidekiq.svg)](https://rubygems.org/gems/sidekiq)
5
+ ![Build](https://github.com/sidekiq/sidekiq/workflows/CI/badge.svg)
5
6
 
6
- Sidekiq is compatible with Resque. It uses the exact same
7
- message format as Resque so it can integrate into an existing Resque processing farm.
8
- You can have Sidekiq and Resque run side-by-side at the same time and
9
- use the Resque client to enqueue messages in Redis to be processed by Sidekiq.
7
+ Simple, efficient background processing for Ruby.
10
8
 
11
- At the same time, Sidekiq uses multithreading so it much more memory efficient than Resque (which forks a new process for every job).
12
- You'll find that you might need 50 200MB resque processes to peg your CPU
13
- whereas one 300MB Sidekiq process will peg the same CPU and perform the
14
- same amount of work. Please see [my blog post on Resque's memory
15
- efficiency](http://blog.carbonfive.com/2011/09/16/improving-resques-memory-efficiency/)
16
- and how I was able to shrink a Carbon Five client's resque processing farm
17
- from 9 machines to 1 machine.
18
-
19
- In sum, if your jobs are well-behaved and threadsafe, Sidekiq is probably a good replacement for Resque. If your jobs are not thread-safe or they leak memory, you may want to continue using Resque, because its forking model gives you more protection.
9
+ Sidekiq uses threads to handle many jobs at the same time in the
10
+ same process. It does not require Rails but will integrate tightly with
11
+ Rails to make background processing dead simple.
20
12
 
21
13
 
22
14
  Requirements
23
15
  -----------------
24
16
 
25
- I test on Ruby 1.9.3 and JRuby 1.6.5 in 1.9 mode. Other versions/VMs are
26
- untested but I will do my best to support them. Ruby 1.8 is not supported.
17
+ - Redis: 6.2+
18
+ - Ruby: MRI 2.7+ or JRuby 9.3+.
19
+
20
+ Sidekiq 7.0 supports Rails 6.0+ but does not require it.
27
21
 
28
22
 
29
23
  Installation
30
24
  -----------------
31
25
 
32
- gem install sidekiq
26
+ bundle add sidekiq
33
27
 
34
28
 
35
29
  Getting Started
36
30
  -----------------
37
31
 
38
- See the [sidekiq home page](http://mperham.github.com/sidekiq) for the simple 4-step process.
32
+ See the [Getting Started wiki page](https://github.com/sidekiq/sidekiq/wiki/Getting-Started) and follow the simple setup process.
33
+ You can watch [this YouTube playlist](https://www.youtube.com/playlist?list=PLjeHh2LSCFrWGT5uVjUuFKAcrcj5kSai1) to learn all about
34
+ Sidekiq and see its features in action. Here's the Web UI:
35
+
36
+ ![Web UI](https://github.com/sidekiq/sidekiq/raw/main/examples/web-ui.png)
37
+
38
+ Performance
39
+ ---------------
40
+
41
+ The benchmark in `bin/sidekiqload` creates 500,000 no-op jobs and drains them as fast as possible, assuming a fixed Redis network latency of 1ms.
42
+ This requires a lot of Redis network I/O and JSON parsing.
43
+ This benchmark is IO-bound so we increase the concurrency to 25.
44
+ If your application is sending lots of emails or performing other network-intensive work, you could see a similar benefit but be careful not to saturate the CPU.
45
+
46
+ Version | Time to process 500k jobs | Throughput (jobs/sec) | Ruby | Concurrency | Job Type
47
+ -----------------|------|---------|---------|------------------------|---
48
+ Sidekiq 7.0.3 | 21.3 sec| 23,500 | 3.2.0+yjit | 30 | Sidekiq::Job
49
+ Sidekiq 7.0.3 | 33.8 sec| 14,700 | 3.2.0+yjit | 30 | ActiveJob 7.0.4
50
+ Sidekiq 7.0.3 | 23.5 sec| 21,300 | 3.2.0 | 30 | Sidekiq::Job
51
+ Sidekiq 7.0.3 | 46.5 sec| 10,700 | 3.2.0 | 30 | ActiveJob 7.0.4
52
+ Sidekiq 7.0.3 | 23.0 sec| 21,700 | 2.7.5 | 30 | Sidekiq::Job
53
+ Sidekiq 7.0.3 | 46.5 sec| 10,850 | 2.7.5 | 30 | ActiveJob 7.0.4
54
+
55
+ Most of Sidekiq's overhead is Redis network I/O.
56
+ ActiveJob adds a notable amount of CPU overhead due to argument deserialization and callbacks.
57
+ Concurrency of 30 was determined experimentally to maximize one CPU without saturating it.
58
+
59
+ Want to Upgrade?
60
+ -------------------
61
+
62
+ Use `bundle up sidekiq` to upgrade Sidekiq and all its dependencies.
63
+ Upgrade notes between each major version can be found in the `docs/` directory.
64
+
65
+ I also sell Sidekiq Pro and Sidekiq Enterprise, extensions to Sidekiq which provide more
66
+ features, a commercial-friendly license and allow you to support high
67
+ quality open source development all at the same time. Please see the
68
+ [Sidekiq](https://sidekiq.org/) homepage for more detail.
39
69
 
40
70
 
41
- More Information
71
+ Problems?
42
72
  -----------------
43
73
 
44
- Please see the [sidekiq wiki](https://github.com/mperham/sidekiq/wiki) for more information.
45
- [#sidekiq on irc.freenode.net](irc://irc.freenode.net/#sidekiq) is dedicated to this project,
46
- but bug reports or feature requests suggestions should still go through [issues on Github](https://github.com/mperham/sidekiq/issues).
74
+ **Please do not directly email any Sidekiq committers with questions or problems.**
75
+ A community is best served when discussions are held in public.
47
76
 
77
+ If you have a problem, please review the [FAQ](https://github.com/sidekiq/sidekiq/wiki/FAQ) and [Troubleshooting](https://github.com/sidekiq/sidekiq/wiki/Problems-and-Troubleshooting) wiki pages.
78
+ Searching the [issues](https://github.com/sidekiq/sidekiq/issues) for your problem is also a good idea.
48
79
 
49
- License
80
+ Sidekiq Pro and Sidekiq Enterprise customers get private email support.
81
+ You can purchase at https://sidekiq.org; email support@contribsys.com for help.
82
+
83
+ Useful resources:
84
+
85
+ * Product documentation is in the [wiki](https://github.com/sidekiq/sidekiq/wiki).
86
+ * Occasional announcements are made to the [@sidekiq](https://ruby.social/@sidekiq) Mastodon account.
87
+ * The [Sidekiq tag](https://stackoverflow.com/questions/tagged/sidekiq) on Stack Overflow has lots of useful Q &amp; A.
88
+
89
+ Every Friday morning is Sidekiq office hour: I video chat and answer questions.
90
+ See the [Sidekiq support page](https://sidekiq.org/support.html) for details.
91
+
92
+ Contributing
50
93
  -----------------
51
94
 
52
- Please see LICENSE for licensing details.
95
+ Please see [the contributing guidelines](https://github.com/sidekiq/sidekiq/blob/main/.github/contributing.md).
53
96
 
54
- <a href='http://www.pledgie.com/campaigns/16623'><img alt='Click here to lend your support to Open Source and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/16623.png?skin_name=chrome' border='0' /></a>
97
+ License
98
+ -----------------
99
+
100
+ Please see [LICENSE.txt](https://github.com/sidekiq/sidekiq/blob/main/LICENSE.txt) for licensing details.
101
+ The license for Sidekiq Pro and Sidekiq Enterprise can be found in [COMM-LICENSE.txt](https://github.com/sidekiq/sidekiq/blob/main/COMM-LICENSE.txt).
55
102
 
56
103
  Author
57
104
  -----------------
58
105
 
59
- Mike Perham, [@mperham](https://twitter.com/mperham), [http://mikeperham.com](http://mikeperham.com)
60
-
106
+ Mike Perham, [@getajobmike](https://ruby.social/@getajobmike) / [@sidekiq](https://ruby.social/@sidekiq), [https://www.mikeperham.com](https://www.mikeperham.com) / [https://www.contribsys.com](https://www.contribsys.com)
data/bin/sidekiq CHANGED
@@ -1,21 +1,37 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- begin
4
- require 'sidekiq/cli'
5
- rescue LoadError
6
- # Better way to do this in dev?
7
- dir = File.expand_path(File.dirname(__FILE__) + '/../lib')
8
- $LOAD_PATH << dir if File.exist?("#{dir}/sidekiq.rb")
9
- require 'sidekiq/cli'
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
+ def integrate_with_systemd
10
+ return unless ENV["NOTIFY_SOCKET"]
11
+
12
+ Sidekiq.configure_server do |config|
13
+ config.logger.info "Enabling systemd notification integration"
14
+ require "sidekiq/sd_notify"
15
+ config.on(:startup) do
16
+ Sidekiq::SdNotify.ready
17
+ end
18
+ config.on(:shutdown) do
19
+ Sidekiq::SdNotify.stopping
20
+ end
21
+ Sidekiq.start_watchdog if Sidekiq::SdNotify.watchdog?
22
+ end
10
23
  end
11
24
 
12
25
  begin
13
26
  cli = Sidekiq::CLI.instance
14
27
  cli.parse
28
+
29
+ integrate_with_systemd
30
+
15
31
  cli.run
16
32
  rescue => e
17
33
  raise e if $DEBUG
18
- STDERR.puts e.message
19
- STDERR.puts e.backtrace.join("\n")
34
+ warn e.message
35
+ warn e.backtrace.join("\n")
20
36
  exit 1
21
37
  end
data/bin/sidekiqload ADDED
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #
4
+ # bin/sidekiqload is a helpful script to load test and
5
+ # performance tune Sidekiq's core. It creates 500,000 no-op
6
+ # jobs and executes them as fast as possible.
7
+ # Example Usage:
8
+ #
9
+ # > RUBY_YJIT_ENABLE=1 LATENCY=0 THREADS=10 bin/sidekiqload
10
+ # Result: Done, 500000 jobs in 20.264945 sec, 24673 jobs/sec
11
+ #
12
+ # Use LATENCY=1 to get a more real world network setup
13
+ # but you'll need to setup and start toxiproxy as noted below.
14
+ #
15
+ # Use AJ=1 to test ActiveJob instead of plain old Sidekiq::Jobs so
16
+ # you can see the runtime performance difference between the two APIs.
17
+ #
18
+ # None of this script is considered a public API and may change over time.
19
+ #
20
+
21
+ # Quiet some warnings we see when running in warning mode:
22
+ # RUBYOPT=-w bundle exec sidekiq
23
+ $TESTING = false
24
+ puts RUBY_DESCRIPTION
25
+ puts(%w[THREADS LATENCY AJ PROFILE].map { |x| "#{x}: #{ENV[x] || "nil"}" }.join(", "))
26
+
27
+ require "ruby-prof" if ENV["PROFILE"]
28
+ require "bundler/setup"
29
+ Bundler.require(:default, :load_test)
30
+
31
+ latency = Integer(ENV["LATENCY"] || 1)
32
+ if latency > 0
33
+ # brew tap shopify/shopify
34
+ # brew install toxiproxy
35
+ # run `toxiproxy-server` in a separate terminal window.
36
+ require "toxiproxy"
37
+ # simulate a non-localhost network for realer-world conditions.
38
+ # adding 1ms of network latency has an ENORMOUS impact on benchmarks
39
+ Toxiproxy.populate([{
40
+ name: "redis",
41
+ listen: "127.0.0.1:6380",
42
+ upstream: "127.0.0.1:6379"
43
+ }])
44
+ end
45
+
46
+ if ENV["AJ"]
47
+ require "active_job"
48
+ puts "Using ActiveJob #{ActiveJob::VERSION::STRING}"
49
+ ActiveJob::Base.queue_adapter = :sidekiq
50
+ ActiveJob::Base.logger.level = Logger::WARN
51
+
52
+ class LoadJob < ActiveJob::Base
53
+ def perform(idx, ts = nil)
54
+ puts(Time.now.to_f - ts) if !ts.nil?
55
+ end
56
+ end
57
+ end
58
+
59
+ class LoadWorker
60
+ include Sidekiq::Job
61
+ sidekiq_options retry: 1
62
+ sidekiq_retry_in do |x|
63
+ 1
64
+ end
65
+
66
+ def perform(idx, ts = nil)
67
+ puts(Time.now.to_f - ts) if !ts.nil?
68
+ # raise idx.to_s if idx % 100 == 1
69
+ end
70
+ end
71
+
72
+ def Process.rss
73
+ `ps -o rss= -p #{Process.pid}`.chomp.to_i
74
+ end
75
+
76
+ class Loader
77
+ def initialize
78
+ @iter = ENV["GC"] ? 10 : 500
79
+ @count = Integer(ENV["COUNT"] || 1_000)
80
+ @latency = Integer(ENV["LATENCY"] || 1)
81
+ end
82
+
83
+ def configure
84
+ @x = Sidekiq.configure_embed do |config|
85
+ config.redis = {db: 13, port: ((@latency > 0) ? 6380 : 6379)}
86
+ config.concurrency = Integer(ENV.fetch("THREADS", "10"))
87
+ # config.redis = { db: 13, port: 6380, driver: :hiredis}
88
+ config.queues = %w[default]
89
+ config.logger.level = Logger::WARN
90
+ config.average_scheduled_poll_interval = 2
91
+ config.reliable! if defined?(Sidekiq::Pro)
92
+ end
93
+
94
+ @self_read, @self_write = IO.pipe
95
+ %w[INT TERM TSTP TTIN].each do |sig|
96
+ trap sig do
97
+ @self_write.puts(sig)
98
+ end
99
+ rescue ArgumentError
100
+ puts "Signal #{sig} not supported"
101
+ end
102
+ end
103
+
104
+ def handle_signal(sig)
105
+ launcher = @x
106
+ Sidekiq.logger.debug "Got #{sig} signal"
107
+ case sig
108
+ when "INT"
109
+ # Handle Ctrl-C in JRuby like MRI
110
+ # http://jira.codehaus.org/browse/JRUBY-4637
111
+ raise Interrupt
112
+ when "TERM"
113
+ # Heroku sends TERM and then waits 30 seconds for process to exit.
114
+ raise Interrupt
115
+ when "TSTP"
116
+ Sidekiq.logger.info "Received TSTP, no longer accepting new work"
117
+ launcher.quiet
118
+ when "TTIN"
119
+ Thread.list.each do |thread|
120
+ Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread["label"]}"
121
+ if thread.backtrace
122
+ Sidekiq.logger.warn thread.backtrace.join("\n")
123
+ else
124
+ Sidekiq.logger.warn "<no backtrace available>"
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ def setup
131
+ Sidekiq.logger.error("Setup RSS: #{Process.rss}")
132
+ Sidekiq.redis { |c| c.flushdb }
133
+ start = Time.now
134
+ if ENV["AJ"]
135
+ @iter.times do
136
+ @count.times do |idx|
137
+ LoadJob.perform_later(idx)
138
+ end
139
+ end
140
+ else
141
+ @iter.times do
142
+ arr = Array.new(@count) { |idx| [idx] }
143
+ Sidekiq::Client.push_bulk("class" => LoadWorker, "args" => arr)
144
+ end
145
+ end
146
+ Sidekiq.logger.warn "Created #{@count * @iter} jobs in #{Time.now - start} sec"
147
+ end
148
+
149
+ def monitor
150
+ @monitor = Thread.new do
151
+ GC.start
152
+ loop do
153
+ sleep 0.2
154
+ qsize = Sidekiq.redis do |conn|
155
+ conn.llen "queue:default"
156
+ end
157
+ total = qsize
158
+ if total == 0
159
+ ending = Time.now - @start
160
+ size = @iter * @count
161
+ Sidekiq.logger.error("Done, #{size} jobs in #{ending} sec, #{(size / ending).to_i} jobs/sec")
162
+ Sidekiq.logger.error("Ending RSS: #{Process.rss}")
163
+ Sidekiq.logger.error("Now here's the latency for three jobs")
164
+
165
+ if ENV["AJ"]
166
+ LoadJob.perform_later(1, Time.now.to_f)
167
+ LoadJob.perform_later(2, Time.now.to_f)
168
+ LoadJob.perform_later(3, Time.now.to_f)
169
+ else
170
+ LoadWorker.perform_async(1, Time.now.to_f)
171
+ LoadWorker.perform_async(2, Time.now.to_f)
172
+ LoadWorker.perform_async(3, Time.now.to_f)
173
+ end
174
+
175
+ sleep 0.1
176
+ @x.stop
177
+ Process.kill("INT", $$)
178
+ break
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ def with_latency(latency, &block)
185
+ Sidekiq.logger.error "Simulating #{latency}ms of latency between Sidekiq and redis"
186
+ if latency > 0
187
+ Toxiproxy[:redis].downstream(:latency, latency: latency).apply(&block)
188
+ else
189
+ yield
190
+ end
191
+ end
192
+
193
+ def run(name)
194
+ Sidekiq.logger.warn("Starting #{name}")
195
+ monitor
196
+
197
+ if ENV["PROFILE"]
198
+ RubyProf.exclude_threads = [@monitor]
199
+ RubyProf.start
200
+ elsif ENV["GC"]
201
+ GC.start
202
+ GC.compact
203
+ GC.disable
204
+ Sidekiq.logger.error("GC Start RSS: #{Process.rss}")
205
+ end
206
+ @start = Time.now
207
+ with_latency(@latency) do
208
+ @x.run
209
+
210
+ while (readable_io = IO.select([@self_read]))
211
+ signal = readable_io.first[0].gets.strip
212
+ handle_signal(signal)
213
+ end
214
+ end
215
+ # normal
216
+ rescue Interrupt
217
+ rescue => e
218
+ raise e if $DEBUG
219
+ warn e.message
220
+ warn e.backtrace.join("\n")
221
+ exit 1
222
+ ensure
223
+ @x.stop
224
+ end
225
+
226
+ def done
227
+ Sidekiq.logger.error("GC End RSS: #{Process.rss}") if ENV["GC"]
228
+ if ENV["PROFILE"]
229
+ Sidekiq.logger.error("Profiling...")
230
+ result = RubyProf.stop
231
+ printer = RubyProf::GraphHtmlPrinter.new(result)
232
+ printer.print(File.new("output.html", "w"), min_percent: 1)
233
+ end
234
+ end
235
+ end
236
+
237
+ ll = Loader.new
238
+ ll.configure
239
+
240
+ if ENV["WARM"]
241
+ ll.setup
242
+ ll.run("warmup")
243
+ end
244
+
245
+ ll.setup
246
+ ll.run("load")
247
+ ll.done
data/bin/sidekiqmon ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "sidekiq/monitor"
4
+
5
+ # disable the Redis connection pool logging
6
+ Sidekiq.default_configuration.logger.level = :warn
7
+
8
+ section = "all"
9
+ section = ARGV[0] if ARGV.size == 1
10
+
11
+ Sidekiq::Monitor::Status.new.display(section)
@@ -0,0 +1,57 @@
1
+ require "rails/generators/named_base"
2
+
3
+ module Sidekiq
4
+ module Generators # :nodoc:
5
+ class JobGenerator < ::Rails::Generators::NamedBase # :nodoc:
6
+ desc "This generator creates a Sidekiq Job in app/sidekiq and a corresponding test"
7
+
8
+ check_class_collision suffix: "Job"
9
+
10
+ def self.default_generator_root
11
+ File.dirname(__FILE__)
12
+ end
13
+
14
+ def create_job_file
15
+ template "job.rb.erb", File.join("app/sidekiq", class_path, "#{file_name}_job.rb")
16
+ end
17
+
18
+ def create_test_file
19
+ return unless test_framework
20
+
21
+ if test_framework == :rspec
22
+ create_job_spec
23
+ else
24
+ create_job_test
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def create_job_spec
31
+ template_file = File.join(
32
+ "spec/sidekiq",
33
+ class_path,
34
+ "#{file_name}_job_spec.rb"
35
+ )
36
+ template "job_spec.rb.erb", template_file
37
+ end
38
+
39
+ def create_job_test
40
+ template_file = File.join(
41
+ "test/sidekiq",
42
+ class_path,
43
+ "#{file_name}_job_test.rb"
44
+ )
45
+ template "job_test.rb.erb", template_file
46
+ end
47
+
48
+ def file_name
49
+ @_file_name ||= super.sub(/_?job\z/i, "")
50
+ end
51
+
52
+ def test_framework
53
+ ::Rails.application.config.generators.options[:rails][:test_framework]
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,9 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Job
3
+ include Sidekiq::Job
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 %>Job, type: :job do
4
+ pending "add some examples to (or delete) #{__FILE__}"
5
+ end
6
+ <% end -%>
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+ <% module_namespacing do -%>
3
+ class <%= class_name %>JobTest < Minitest::Test
4
+ def test_example
5
+ skip "add some examples to (or delete) #{__FILE__}"
6
+ end
7
+ end
8
+ <% end -%>