sidekiq-unique-jobs 4.0.18 → 7.1.28

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

Potentially problematic release.


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

Files changed (296) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1889 -94
  3. data/LICENSE.txt +21 -0
  4. data/README.md +927 -119
  5. data/bin/uniquejobs +7 -0
  6. data/lib/sidekiq-unique-jobs.rb +2 -78
  7. data/lib/sidekiq_unique_jobs/batch_delete.rb +124 -0
  8. data/lib/sidekiq_unique_jobs/changelog.rb +78 -0
  9. data/lib/sidekiq_unique_jobs/cli.rb +79 -21
  10. data/lib/sidekiq_unique_jobs/config.rb +310 -14
  11. data/lib/sidekiq_unique_jobs/connection.rb +23 -0
  12. data/lib/sidekiq_unique_jobs/constants.rb +52 -16
  13. data/lib/sidekiq_unique_jobs/core_ext.rb +114 -33
  14. data/lib/sidekiq_unique_jobs/deprecation.rb +65 -0
  15. data/lib/sidekiq_unique_jobs/digests.rb +111 -0
  16. data/lib/sidekiq_unique_jobs/exceptions.rb +105 -0
  17. data/lib/sidekiq_unique_jobs/expiring_digests.rb +14 -0
  18. data/lib/sidekiq_unique_jobs/job.rb +58 -0
  19. data/lib/sidekiq_unique_jobs/json.rb +47 -0
  20. data/lib/sidekiq_unique_jobs/key.rb +98 -0
  21. data/lib/sidekiq_unique_jobs/lock/base_lock.rb +165 -0
  22. data/lib/sidekiq_unique_jobs/lock/client_validator.rb +28 -0
  23. data/lib/sidekiq_unique_jobs/lock/server_validator.rb +27 -0
  24. data/lib/sidekiq_unique_jobs/lock/until_and_while_executing.rb +65 -7
  25. data/lib/sidekiq_unique_jobs/lock/until_executed.rb +34 -64
  26. data/lib/sidekiq_unique_jobs/lock/until_executing.rb +37 -4
  27. data/lib/sidekiq_unique_jobs/lock/until_expired.rb +42 -0
  28. data/lib/sidekiq_unique_jobs/lock/validator.rb +96 -0
  29. data/lib/sidekiq_unique_jobs/lock/while_executing.rb +53 -35
  30. data/lib/sidekiq_unique_jobs/lock/while_executing_reject.rb +21 -0
  31. data/lib/sidekiq_unique_jobs/lock.rb +338 -6
  32. data/lib/sidekiq_unique_jobs/lock_args.rb +127 -0
  33. data/lib/sidekiq_unique_jobs/lock_config.rb +126 -0
  34. data/lib/sidekiq_unique_jobs/lock_digest.rb +79 -0
  35. data/lib/sidekiq_unique_jobs/lock_info.rb +68 -0
  36. data/lib/sidekiq_unique_jobs/lock_timeout.rb +62 -0
  37. data/lib/sidekiq_unique_jobs/lock_ttl.rb +77 -0
  38. data/lib/sidekiq_unique_jobs/locksmith.rb +383 -0
  39. data/lib/sidekiq_unique_jobs/logging/middleware_context.rb +44 -0
  40. data/lib/sidekiq_unique_jobs/logging.rb +236 -0
  41. data/lib/sidekiq_unique_jobs/lua/delete.lua +51 -0
  42. data/lib/sidekiq_unique_jobs/lua/delete_by_digest.lua +42 -0
  43. data/lib/sidekiq_unique_jobs/lua/delete_job_by_digest.lua +38 -0
  44. data/lib/sidekiq_unique_jobs/lua/find_digest_in_queues.lua +26 -0
  45. data/lib/sidekiq_unique_jobs/lua/lock.lua +99 -0
  46. data/lib/sidekiq_unique_jobs/lua/lock_until_expired.lua +92 -0
  47. data/lib/sidekiq_unique_jobs/lua/locked.lua +35 -0
  48. data/lib/sidekiq_unique_jobs/lua/queue.lua +87 -0
  49. data/lib/sidekiq_unique_jobs/lua/reap_orphans.lua +122 -0
  50. data/lib/sidekiq_unique_jobs/lua/shared/_common.lua +40 -0
  51. data/lib/sidekiq_unique_jobs/lua/shared/_current_time.lua +8 -0
  52. data/lib/sidekiq_unique_jobs/lua/shared/_delete_from_queue.lua +22 -0
  53. data/lib/sidekiq_unique_jobs/lua/shared/_delete_from_sorted_set.lua +18 -0
  54. data/lib/sidekiq_unique_jobs/lua/shared/_find_digest_in_process_set.lua +53 -0
  55. data/lib/sidekiq_unique_jobs/lua/shared/_find_digest_in_queues.lua +43 -0
  56. data/lib/sidekiq_unique_jobs/lua/shared/_find_digest_in_sorted_set.lua +24 -0
  57. data/lib/sidekiq_unique_jobs/lua/shared/_hgetall.lua +13 -0
  58. data/lib/sidekiq_unique_jobs/lua/shared/_upgrades.lua +3 -0
  59. data/lib/sidekiq_unique_jobs/lua/unlock.lua +107 -0
  60. data/lib/sidekiq_unique_jobs/lua/update_version.lua +40 -0
  61. data/lib/sidekiq_unique_jobs/lua/upgrade.lua +68 -0
  62. data/lib/sidekiq_unique_jobs/middleware/client.rb +42 -0
  63. data/lib/sidekiq_unique_jobs/middleware/server.rb +31 -0
  64. data/lib/sidekiq_unique_jobs/middleware.rb +34 -29
  65. data/lib/sidekiq_unique_jobs/normalizer.rb +11 -1
  66. data/lib/sidekiq_unique_jobs/on_conflict/log.rb +24 -0
  67. data/lib/sidekiq_unique_jobs/on_conflict/null_strategy.rb +16 -0
  68. data/lib/sidekiq_unique_jobs/on_conflict/raise.rb +17 -0
  69. data/lib/sidekiq_unique_jobs/on_conflict/reject.rb +118 -0
  70. data/lib/sidekiq_unique_jobs/on_conflict/replace.rb +82 -0
  71. data/lib/sidekiq_unique_jobs/on_conflict/reschedule.rb +35 -0
  72. data/lib/sidekiq_unique_jobs/on_conflict/strategy.rb +51 -0
  73. data/lib/sidekiq_unique_jobs/on_conflict.rb +44 -0
  74. data/lib/sidekiq_unique_jobs/options_with_fallback.rb +54 -31
  75. data/lib/sidekiq_unique_jobs/orphans/lua_reaper.rb +29 -0
  76. data/lib/sidekiq_unique_jobs/orphans/manager.rb +241 -0
  77. data/lib/sidekiq_unique_jobs/orphans/null_reaper.rb +24 -0
  78. data/lib/sidekiq_unique_jobs/orphans/observer.rb +42 -0
  79. data/lib/sidekiq_unique_jobs/orphans/reaper.rb +114 -0
  80. data/lib/sidekiq_unique_jobs/orphans/reaper_resurrector.rb +170 -0
  81. data/lib/sidekiq_unique_jobs/orphans/ruby_reaper.rb +298 -0
  82. data/lib/sidekiq_unique_jobs/redis/entity.rb +112 -0
  83. data/lib/sidekiq_unique_jobs/redis/hash.rb +56 -0
  84. data/lib/sidekiq_unique_jobs/redis/list.rb +32 -0
  85. data/lib/sidekiq_unique_jobs/redis/set.rb +32 -0
  86. data/lib/sidekiq_unique_jobs/redis/sorted_set.rb +86 -0
  87. data/lib/sidekiq_unique_jobs/redis/string.rb +51 -0
  88. data/lib/sidekiq_unique_jobs/redis.rb +11 -0
  89. data/lib/sidekiq_unique_jobs/reflectable.rb +26 -0
  90. data/lib/sidekiq_unique_jobs/reflections.rb +79 -0
  91. data/lib/sidekiq_unique_jobs/rspec/matchers/have_valid_sidekiq_options.rb +51 -0
  92. data/lib/sidekiq_unique_jobs/rspec/matchers.rb +26 -0
  93. data/lib/sidekiq_unique_jobs/script/caller.rb +127 -0
  94. data/lib/sidekiq_unique_jobs/script.rb +15 -0
  95. data/lib/sidekiq_unique_jobs/server.rb +61 -0
  96. data/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb +116 -104
  97. data/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb +304 -0
  98. data/lib/sidekiq_unique_jobs/sidekiq_worker_methods.rb +84 -0
  99. data/lib/sidekiq_unique_jobs/testing.rb +115 -50
  100. data/lib/sidekiq_unique_jobs/timer_task.rb +299 -0
  101. data/lib/sidekiq_unique_jobs/timing.rb +58 -0
  102. data/lib/sidekiq_unique_jobs/unlockable.rb +29 -33
  103. data/lib/sidekiq_unique_jobs/update_version.rb +25 -0
  104. data/lib/sidekiq_unique_jobs/upgrade_locks.rb +155 -0
  105. data/lib/sidekiq_unique_jobs/version.rb +5 -1
  106. data/lib/sidekiq_unique_jobs/version_check.rb +114 -0
  107. data/lib/sidekiq_unique_jobs/web/helpers.rb +173 -0
  108. data/lib/sidekiq_unique_jobs/web/views/_paging.erb +10 -0
  109. data/lib/sidekiq_unique_jobs/web/views/changelogs.erb +54 -0
  110. data/lib/sidekiq_unique_jobs/web/views/lock.erb +108 -0
  111. data/lib/sidekiq_unique_jobs/web/views/locks.erb +54 -0
  112. data/lib/sidekiq_unique_jobs/web.rb +109 -0
  113. data/lib/sidekiq_unique_jobs.rb +81 -0
  114. data/lib/tasks/changelog.rake +23 -0
  115. metadata +173 -251
  116. data/.codeclimate.yml +0 -22
  117. data/.dockerignore +0 -4
  118. data/.editorconfig +0 -14
  119. data/.fasterer.yml +0 -23
  120. data/.gitignore +0 -14
  121. data/.rspec +0 -3
  122. data/.rubocop.yml +0 -45
  123. data/.simplecov +0 -12
  124. data/.travis.yml +0 -43
  125. data/Appraisals +0 -31
  126. data/Gemfile +0 -16
  127. data/LICENSE +0 -13
  128. data/Rakefile +0 -12
  129. data/bin/bench +0 -19
  130. data/bin/jobs +0 -6
  131. data/circle.yml +0 -38
  132. data/gemfiles/sidekiq_2.15.gemfile +0 -9
  133. data/gemfiles/sidekiq_2.16.gemfile +0 -9
  134. data/gemfiles/sidekiq_2.17.gemfile +0 -19
  135. data/gemfiles/sidekiq_3.0.gemfile +0 -19
  136. data/gemfiles/sidekiq_3.1.gemfile +0 -19
  137. data/gemfiles/sidekiq_3.2.gemfile +0 -19
  138. data/gemfiles/sidekiq_3.3.gemfile +0 -19
  139. data/gemfiles/sidekiq_4.0.gemfile +0 -19
  140. data/gemfiles/sidekiq_4.1.gemfile +0 -19
  141. data/gemfiles/sidekiq_develop.gemfile +0 -19
  142. data/lib/sidekiq/simulator.rb +0 -75
  143. data/lib/sidekiq_unique_jobs/client/middleware.rb +0 -41
  144. data/lib/sidekiq_unique_jobs/lock/until_timeout.rb +0 -15
  145. data/lib/sidekiq_unique_jobs/run_lock_failed.rb +0 -1
  146. data/lib/sidekiq_unique_jobs/script_mock.rb +0 -68
  147. data/lib/sidekiq_unique_jobs/scripts.rb +0 -49
  148. data/lib/sidekiq_unique_jobs/server/middleware.rb +0 -34
  149. data/lib/sidekiq_unique_jobs/testing/sidekiq_overrides.rb +0 -70
  150. data/lib/sidekiq_unique_jobs/timeout_calculator.rb +0 -65
  151. data/lib/sidekiq_unique_jobs/unique_args.rb +0 -134
  152. data/lib/sidekiq_unique_jobs/util.rb +0 -91
  153. data/rails_example/.env +0 -12
  154. data/rails_example/.gitignore +0 -13
  155. data/rails_example/.rspec +0 -2
  156. data/rails_example/Gemfile +0 -34
  157. data/rails_example/Procfile +0 -2
  158. data/rails_example/README.rdoc +0 -28
  159. data/rails_example/Rakefile +0 -6
  160. data/rails_example/app/assets/images/.keep +0 -0
  161. data/rails_example/app/assets/javascripts/application.js +0 -16
  162. data/rails_example/app/assets/stylesheets/application.css +0 -15
  163. data/rails_example/app/channels/appearance_channel.rb +0 -17
  164. data/rails_example/app/channels/application_cable/channel.rb +0 -4
  165. data/rails_example/app/channels/application_cable/connection.rb +0 -9
  166. data/rails_example/app/channels/post_channel.rb +0 -5
  167. data/rails_example/app/controllers/application_controller.rb +0 -5
  168. data/rails_example/app/controllers/concerns/.keep +0 -0
  169. data/rails_example/app/controllers/work_controller.rb +0 -13
  170. data/rails_example/app/helpers/application_helper.rb +0 -2
  171. data/rails_example/app/mailers/.keep +0 -0
  172. data/rails_example/app/models/.keep +0 -0
  173. data/rails_example/app/models/application_record.rb +0 -3
  174. data/rails_example/app/models/concerns/.keep +0 -0
  175. data/rails_example/app/models/guest.rb +0 -21
  176. data/rails_example/app/models/post.rb +0 -2
  177. data/rails_example/app/views/layouts/application.html.erb +0 -15
  178. data/rails_example/app/workers/simple_worker.rb +0 -12
  179. data/rails_example/app/workers/spawn_simple_worker.rb +0 -7
  180. data/rails_example/bin/bundle +0 -3
  181. data/rails_example/bin/check_or_setup_db +0 -57
  182. data/rails_example/bin/docker-setup +0 -20
  183. data/rails_example/bin/rails +0 -4
  184. data/rails_example/bin/rake +0 -4
  185. data/rails_example/bin/setup +0 -34
  186. data/rails_example/bin/update +0 -29
  187. data/rails_example/cable.ru +0 -6
  188. data/rails_example/common-services.yml +0 -50
  189. data/rails_example/config/application.rb +0 -27
  190. data/rails_example/config/boot.rb +0 -3
  191. data/rails_example/config/cable.yml +0 -9
  192. data/rails_example/config/database.docker.yml +0 -12
  193. data/rails_example/config/database.yml +0 -19
  194. data/rails_example/config/environment.rb +0 -5
  195. data/rails_example/config/environments/development.rb +0 -54
  196. data/rails_example/config/environments/production.rb +0 -86
  197. data/rails_example/config/environments/test.rb +0 -42
  198. data/rails_example/config/initializers/application_controller_renderer.rb +0 -6
  199. data/rails_example/config/initializers/assets.rb +0 -11
  200. data/rails_example/config/initializers/backtrace_silencers.rb +0 -9
  201. data/rails_example/config/initializers/cookies_serializer.rb +0 -5
  202. data/rails_example/config/initializers/filter_parameter_logging.rb +0 -4
  203. data/rails_example/config/initializers/inflections.rb +0 -16
  204. data/rails_example/config/initializers/mime_types.rb +0 -4
  205. data/rails_example/config/initializers/new_framework_defaults.rb +0 -23
  206. data/rails_example/config/initializers/session_store.rb +0 -3
  207. data/rails_example/config/initializers/sidekiq.rb +0 -13
  208. data/rails_example/config/initializers/wrap_parameters.rb +0 -14
  209. data/rails_example/config/locales/en.yml +0 -23
  210. data/rails_example/config/puma.rb +0 -38
  211. data/rails_example/config/routes.rb +0 -6
  212. data/rails_example/config/secrets.yml +0 -22
  213. data/rails_example/config/sidekiq.yml +0 -6
  214. data/rails_example/config/spring.rb +0 -6
  215. data/rails_example/config.ru +0 -4
  216. data/rails_example/db/migrate/20160724111322_create_posts.rb +0 -12
  217. data/rails_example/db/schema.rb +0 -25
  218. data/rails_example/db/seeds.rb +0 -7
  219. data/rails_example/dev-entrypoint.sh +0 -55
  220. data/rails_example/dev.env +0 -12
  221. data/rails_example/docker/rails.Dockerfile +0 -27
  222. data/rails_example/docker-compose.yml +0 -90
  223. data/rails_example/lib/assets/.keep +0 -0
  224. data/rails_example/lib/tasks/.keep +0 -0
  225. data/rails_example/log/.keep +0 -0
  226. data/rails_example/public/404.html +0 -67
  227. data/rails_example/public/422.html +0 -67
  228. data/rails_example/public/500.html +0 -66
  229. data/rails_example/public/favicon.ico +0 -0
  230. data/rails_example/public/robots.txt +0 -5
  231. data/rails_example/simple.ru +0 -12
  232. data/rails_example/spec/controllers/work_controller_spec.rb +0 -172
  233. data/rails_example/spec/factories/posts.rb +0 -8
  234. data/rails_example/spec/models/post_spec.rb +0 -4
  235. data/rails_example/spec/rails_helper.rb +0 -21
  236. data/rails_example/spec/spec_helper.rb +0 -20
  237. data/rails_example/spec/support/sidekiq_meta.rb +0 -12
  238. data/rails_example/spec/workers/simple_worker_spec.rb +0 -4
  239. data/rails_example/vendor/assets/javascripts/.keep +0 -0
  240. data/rails_example/vendor/assets/stylesheets/.keep +0 -0
  241. data/redis/acquire_lock.lua +0 -19
  242. data/redis/release_lock.lua +0 -16
  243. data/redis/synchronize.lua +0 -16
  244. data/sidekiq-unique-jobs.gemspec +0 -25
  245. data/spec/celluloid_with_fallback.rb +0 -18
  246. data/spec/jobs/another_unique_job.rb +0 -13
  247. data/spec/jobs/custom_queue_job.rb +0 -6
  248. data/spec/jobs/custom_queue_job_with_filter_method.rb +0 -7
  249. data/spec/jobs/custom_queue_job_with_filter_proc.rb +0 -10
  250. data/spec/jobs/expiring_job.rb +0 -4
  251. data/spec/jobs/inline_worker.rb +0 -8
  252. data/spec/jobs/just_a_worker.rb +0 -8
  253. data/spec/jobs/long_running_job.rb +0 -7
  254. data/spec/jobs/main_job.rb +0 -8
  255. data/spec/jobs/my_job.rb +0 -12
  256. data/spec/jobs/my_unique_job.rb +0 -12
  257. data/spec/jobs/my_unique_job_with_filter_method.rb +0 -17
  258. data/spec/jobs/my_unique_job_with_filter_proc.rb +0 -15
  259. data/spec/jobs/notify_worker.rb +0 -10
  260. data/spec/jobs/plain_class.rb +0 -4
  261. data/spec/jobs/simple_worker.rb +0 -11
  262. data/spec/jobs/spawn_simple_worker.rb +0 -8
  263. data/spec/jobs/test_class.rb +0 -4
  264. data/spec/jobs/unique_job_with_filter_method.rb +0 -18
  265. data/spec/jobs/unique_on_all_queues_job.rb +0 -13
  266. data/spec/jobs/until_and_while_executing_job.rb +0 -8
  267. data/spec/jobs/until_executed_job.rb +0 -17
  268. data/spec/jobs/until_executing_job.rb +0 -8
  269. data/spec/jobs/until_global_timeout_job.rb +0 -8
  270. data/spec/jobs/until_timeout_job.rb +0 -8
  271. data/spec/jobs/while_executing_job.rb +0 -12
  272. data/spec/lib/sidekiq_unique_jobs/client/middleware_spec.rb +0 -321
  273. data/spec/lib/sidekiq_unique_jobs/core_ext_spec.rb +0 -25
  274. data/spec/lib/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb +0 -43
  275. data/spec/lib/sidekiq_unique_jobs/lock/until_executed_spec.rb +0 -37
  276. data/spec/lib/sidekiq_unique_jobs/lock/until_timeout_spec.rb +0 -26
  277. data/spec/lib/sidekiq_unique_jobs/lock/while_executing_spec.rb +0 -86
  278. data/spec/lib/sidekiq_unique_jobs/normalizer_spec.rb +0 -21
  279. data/spec/lib/sidekiq_unique_jobs/options_with_fallback_spec.rb +0 -113
  280. data/spec/lib/sidekiq_unique_jobs/queue_lock_timeout_calculator_spec.rb +0 -47
  281. data/spec/lib/sidekiq_unique_jobs/run_lock_timeout_calculator_spec.rb +0 -36
  282. data/spec/lib/sidekiq_unique_jobs/script_mock_spec.rb +0 -84
  283. data/spec/lib/sidekiq_unique_jobs/scripts_spec.rb +0 -77
  284. data/spec/lib/sidekiq_unique_jobs/server/middleware_spec.rb +0 -83
  285. data/spec/lib/sidekiq_unique_jobs/sidekiq_testing_enabled_spec.rb +0 -181
  286. data/spec/lib/sidekiq_unique_jobs/sidekiq_unique_ext_spec.rb +0 -80
  287. data/spec/lib/sidekiq_unique_jobs/sidekiq_unique_jobs_spec.rb +0 -41
  288. data/spec/lib/sidekiq_unique_jobs/timeout_calculator_spec.rb +0 -70
  289. data/spec/lib/sidekiq_unique_jobs/unique_args_spec.rb +0 -131
  290. data/spec/lib/sidekiq_unique_jobs/unlockable_spec.rb +0 -4
  291. data/spec/lib/sidekiq_unique_jobs/util_spec.rb +0 -53
  292. data/spec/spec_helper.rb +0 -65
  293. data/spec/support/matchers/redis_matchers.rb +0 -19
  294. data/spec/support/ruby_meta.rb +0 -10
  295. data/spec/support/sidekiq_meta.rb +0 -31
  296. data/spec/support/unique_macros.rb +0 -71
@@ -1,12 +1,70 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SidekiqUniqueJobs
2
- module Lock
3
- class UntilAndWhileExecuting < UntilExecuting
4
- def execute(callback)
5
- lock = WhileExecuting.new(item, redis_pool)
6
- lock.synchronize do
7
- callback.call if unlock(:server)
8
- yield
4
+ class Lock
5
+ # Locks jobs while the job is executing in the server process
6
+ # - Locks on perform_in or perform_async (see {UntilExecuting})
7
+ # - Unlocks before yielding to the worker's perform method (see {UntilExecuting})
8
+ # - Locks before yielding to the worker's perform method (see {WhileExecuting})
9
+ # - Unlocks after yielding to the worker's perform method (see {WhileExecuting})
10
+ #
11
+ # See {#lock} for more information about the client.
12
+ # See {#execute} for more information about the server
13
+ #
14
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
15
+ class UntilAndWhileExecuting < BaseLock
16
+ #
17
+ # Locks a sidekiq job
18
+ #
19
+ # @note Will call a conflict strategy if lock can't be achieved.
20
+ #
21
+ # @return [String, nil] the locked jid when properly locked, else nil.
22
+ #
23
+ # @yield to the caller when given a block
24
+ #
25
+ def lock(origin: :client, &block)
26
+ unless (token = locksmith.lock)
27
+ reflect(:lock_failed, item)
28
+ call_strategy(origin: origin, &block)
29
+
30
+ return
9
31
  end
32
+
33
+ yield if block
34
+
35
+ token
36
+ end
37
+
38
+ # Executes in the Sidekiq server process
39
+ # @yield to the worker class perform method
40
+ def execute
41
+ if locksmith.unlock
42
+ # ensure_relocked do
43
+ runtime_lock.execute { return yield }
44
+ # end
45
+ else
46
+ reflect(:unlock_failed, item)
47
+ end
48
+ rescue Exception # rubocop:disable Lint/RescueException
49
+ reflect(:execution_failed, item)
50
+ locksmith.lock(wait: 2)
51
+
52
+ raise
53
+ end
54
+
55
+ private
56
+
57
+ def ensure_relocked
58
+ yield
59
+ rescue Exception # rubocop:disable Lint/RescueException
60
+ reflect(:execution_failed, item)
61
+ locksmith.lock
62
+
63
+ raise
64
+ end
65
+
66
+ def runtime_lock
67
+ @runtime_lock ||= SidekiqUniqueJobs::Lock::WhileExecuting.new(item.dup, callback, redis_pool)
10
68
  end
11
69
  end
12
70
  end
@@ -1,77 +1,47 @@
1
- module SidekiqUniqueJobs
2
- module Lock
3
- class UntilExecuted
4
- OK ||= 'OK'.freeze
5
-
6
- include SidekiqUniqueJobs::Unlockable
7
-
8
- extend Forwardable
9
- def_delegators :Sidekiq, :logger
10
-
11
- def initialize(item, redis_pool = nil)
12
- @item = item
13
- @redis_pool = redis_pool
14
- end
1
+ # frozen_string_literal: true
15
2
 
16
- def execute(callback, &blk)
17
- operative = true
18
- send(:after_yield_yield, &blk)
19
- rescue Sidekiq::Shutdown
20
- operative = false
21
- raise
22
- ensure
23
- if operative && unlock(:server)
24
- callback.call
25
- else
26
- logger.fatal { "the unique_key: #{unique_key} needs to be unlocked manually" }
3
+ module SidekiqUniqueJobs
4
+ class Lock
5
+ # Locks jobs until the server is done executing the job
6
+ # - Locks on perform_in or perform_async
7
+ # - Unlocks after yielding to the worker's perform method
8
+ #
9
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
10
+ class UntilExecuted < BaseLock
11
+ #
12
+ # Locks a sidekiq job
13
+ #
14
+ # @note Will call a conflict strategy if lock can't be achieved.
15
+ #
16
+ # @return [String, nil] the locked jid when properly locked, else nil.
17
+ #
18
+ # @yield to the caller when given a block
19
+ #
20
+ def lock(&block)
21
+ unless (token = locksmith.lock)
22
+ reflect(:lock_failed, item)
23
+ call_strategy(origin: :client, &block)
24
+
25
+ return
27
26
  end
28
- end
29
27
 
30
- def unlock(scope)
31
- unless [:server, :api, :test].include?(scope)
32
- raise ArgumentError, "#{scope} middleware can't #{__method__} #{unique_key}"
33
- end
28
+ yield if block
34
29
 
35
- unlock_by_key(unique_key, item[JID_KEY], redis_pool)
30
+ token
36
31
  end
37
32
 
38
- # rubocop:disable MethodLength
39
- def lock(scope)
40
- if scope.to_sym != :client
41
- raise ArgumentError, "#{scope} middleware can't #{__method__} #{unique_key}"
33
+ # Executes in the Sidekiq server process
34
+ # @yield to the worker class perform method
35
+ def execute
36
+ executed = locksmith.execute do
37
+ yield
38
+ unlock_and_callback
42
39
  end
43
40
 
44
- result = Scripts.call(:acquire_lock, redis_pool,
45
- keys: [unique_key],
46
- argv: [item[JID_KEY], max_lock_time])
47
- case result
48
- when 1
49
- logger.debug { "successfully locked #{unique_key} for #{max_lock_time} seconds" }
50
- true
51
- when 0
52
- logger.debug { "failed to acquire lock for #{unique_key}" }
53
- false
54
- else
55
- raise "#{__method__} returned an unexpected value (#{result})"
56
- end
57
- end
58
- # rubocop:enable MethodLength
59
-
60
- def unique_key
61
- @unique_key ||= UniqueArgs.digest(item)
62
- end
41
+ reflect(:execution_failed, item) unless executed
63
42
 
64
- def max_lock_time
65
- @max_lock_time ||= QueueLockTimeoutCalculator.for_item(item).seconds
43
+ nil
66
44
  end
67
-
68
- def after_yield_yield
69
- yield
70
- end
71
-
72
- private
73
-
74
- attr_reader :item, :redis_pool
75
45
  end
76
46
  end
77
47
  end
@@ -1,9 +1,42 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SidekiqUniqueJobs
2
- module Lock
3
- class UntilExecuting < UntilExecuted
4
- def execute(callback, &_block)
5
- callback.call if unlock(:server)
4
+ class Lock
5
+ # Locks jobs until {#execute} starts
6
+ # - Locks on perform_in or perform_async
7
+ # - Unlocks before yielding to the worker's perform method
8
+ #
9
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
10
+ class UntilExecuting < BaseLock
11
+ #
12
+ # Locks a sidekiq job
13
+ #
14
+ # @note Will call a conflict strategy if lock can't be achieved.
15
+ #
16
+ # @return [String, nil] the locked jid when properly locked, else nil.
17
+ #
18
+ def lock(&block)
19
+ unless (token = locksmith.lock)
20
+ reflect(:lock_failed, item)
21
+ call_strategy(origin: :client, &block)
22
+
23
+ return
24
+ end
25
+
26
+ yield if block
27
+
28
+ token
29
+ end
30
+
31
+ # Executes in the Sidekiq server process
32
+ # @yield to the worker class perform method
33
+ def execute
34
+ callback_safely if locksmith.unlock
6
35
  yield
36
+ rescue StandardError => ex
37
+ reflect(:execution_failed, item, ex)
38
+ locksmith.lock(wait: 1)
39
+ raise
7
40
  end
8
41
  end
9
42
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ class Lock
5
+ #
6
+ # UntilExpired locks until the job expires
7
+ #
8
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
9
+ #
10
+ class UntilExpired < UntilExecuted
11
+ #
12
+ # Locks a sidekiq job
13
+ #
14
+ # @note Will call a conflict strategy if lock can't be achieved.
15
+ #
16
+ # @return [String, nil] the locked jid when properly locked, else nil.
17
+ #
18
+ # @yield to the caller when given a block
19
+ #
20
+ def lock(&block)
21
+ unless (token = locksmith.lock)
22
+ reflect(:lock_failed, item)
23
+ call_strategy(origin: :client, &block)
24
+
25
+ return
26
+ end
27
+
28
+ yield if block
29
+
30
+ token
31
+ end
32
+
33
+ # Executes in the Sidekiq server process
34
+ # @yield to the worker class perform method
35
+ def execute(&block)
36
+ executed = locksmith.execute(&block)
37
+
38
+ reflect(:execution_failed, item) unless executed
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ class Lock
5
+ #
6
+ # Validator base class to avoid some duplication
7
+ #
8
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
9
+ #
10
+ class Validator
11
+ #
12
+ # @return [Hash] a hash mapping of deprecated keys and their new value
13
+ DEPRECATED_KEYS = {
14
+ UNIQUE.to_sym => LOCK.to_sym,
15
+ UNIQUE_ARGS.to_sym => LOCK_ARGS_METHOD.to_sym,
16
+ LOCK_ARGS.to_sym => LOCK_ARGS_METHOD.to_sym,
17
+ UNIQUE_PREFIX.to_sym => LOCK_PREFIX.to_sym,
18
+ }.freeze
19
+
20
+ #
21
+ # Shorthand for `new(options).validate`
22
+ #
23
+ # @param [Hash] options the sidekiq_options for the worker being validated
24
+ #
25
+ # @return [LockConfig] the lock configuration with errors if any
26
+ #
27
+ def self.validate(options)
28
+ new(options).validate
29
+ end
30
+
31
+ #
32
+ # @!attribute [r] lock_config
33
+ # @return [LockConfig] the lock configuration for this worker
34
+ attr_reader :lock_config
35
+
36
+ #
37
+ # Initialize a new validator
38
+ #
39
+ # @param [Hash] options the sidekiq_options for the worker being validated
40
+ #
41
+ def initialize(options)
42
+ @options = options.transform_keys(&:to_sym)
43
+ @lock_config = LockConfig.new(options)
44
+ handle_deprecations
45
+ end
46
+
47
+ #
48
+ # Validate the workers lock configuration
49
+ #
50
+ #
51
+ # @return [LockConfig] the lock configuration with errors if any
52
+ #
53
+ def validate
54
+ case lock_config.type
55
+ when :while_executing
56
+ validate_server
57
+ when :until_executing
58
+ validate_client
59
+ else
60
+ validate_client
61
+ validate_server
62
+ end
63
+
64
+ lock_config
65
+ end
66
+
67
+ #
68
+ # Validate deprecated keys
69
+ # adds useful information about how to proceed with fixing handle_deprecations
70
+ #
71
+ # @return [void]
72
+ #
73
+ def handle_deprecations
74
+ DEPRECATED_KEYS.each do |old, new|
75
+ next unless @options.key?(old)
76
+
77
+ lock_config.errors[old] = "is deprecated, use `#{new}: #{@options[old]}` instead."
78
+ end
79
+ end
80
+
81
+ #
82
+ # Validates the client configuration
83
+ #
84
+ def validate_client
85
+ ClientValidator.validate(lock_config)
86
+ end
87
+
88
+ #
89
+ # Validates the server configuration
90
+ #
91
+ def validate_server
92
+ ServerValidator.validate(lock_config)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -1,49 +1,67 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SidekiqUniqueJobs
2
- module Lock
3
- class WhileExecuting
4
- def self.synchronize(item, redis_pool = nil)
5
- new(item, redis_pool).synchronize { yield }
6
- end
4
+ class Lock
5
+ # Locks jobs while the job is executing in the server process
6
+ # - Locks before yielding to the worker's perform method
7
+ # - Unlocks after yielding to the worker's perform method
8
+ #
9
+ # See {#lock} for more information about the client.
10
+ # See {#execute} for more information about the server
11
+ #
12
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
13
+ class WhileExecuting < BaseLock
14
+ RUN_SUFFIX = ":RUN"
7
15
 
8
- def initialize(item, redis_pool = nil)
9
- @item = item
10
- @mutex = Mutex.new
11
- @redis_pool = redis_pool
12
- @unique_digest = "#{create_digest}:run"
13
- end
16
+ include SidekiqUniqueJobs::OptionsWithFallback
17
+ include SidekiqUniqueJobs::Logging::Middleware
14
18
 
15
- def synchronize
16
- @mutex.lock
17
- sleep 0.001 until locked?
18
-
19
- yield
20
- rescue Sidekiq::Shutdown
21
- logger.fatal { "the unique_key: #{@unique_digest} needs to be unlocked manually" }
22
- raise
23
- ensure
24
- SidekiqUniqueJobs.connection(@redis_pool) { |c| c.del @unique_digest }
25
- @mutex.unlock
19
+ # @param [Hash] item the Sidekiq job hash
20
+ # @param [Proc] callback callback to call after unlock
21
+ # @param [Sidekiq::RedisConnection, ConnectionPool] redis_pool the redis connection
22
+ #
23
+ def initialize(item, callback, redis_pool = nil)
24
+ super(item, callback, redis_pool)
25
+ append_unique_key_suffix
26
26
  end
27
27
 
28
- def locked?
29
- Scripts.call(:synchronize, @redis_pool,
30
- keys: [@unique_digest],
31
- argv: [Time.now.to_i, max_lock_time]) == 1
32
- end
28
+ # Simulate that a client lock was achieved.
29
+ # These locks should only ever be created in the server process.
30
+ # @return [true] always returns true
31
+ def lock
32
+ job_id = item[JID]
33
+ yield if block_given?
33
34
 
34
- def max_lock_time
35
- @max_lock_time ||= RunLockTimeoutCalculator.for_item(@item).seconds
35
+ job_id
36
36
  end
37
37
 
38
- def execute(_callback)
39
- synchronize do
40
- yield
38
+ # Executes in the Sidekiq server process.
39
+ # These jobs are locked in the server process not from the client
40
+ # @yield to the worker class perform method
41
+ def execute(&block)
42
+ with_logging_context do
43
+ executed = locksmith.execute do
44
+ yield
45
+ callback_safely if locksmith.unlock
46
+ ensure
47
+ locksmith.unlock
48
+ end
49
+
50
+ unless executed
51
+ reflect(:execution_failed, item)
52
+ call_strategy(origin: :server, &block)
53
+ end
41
54
  end
42
55
  end
43
56
 
44
- def create_digest
45
- @unique_digest ||= @item[UNIQUE_DIGEST_KEY]
46
- @unique_digest ||= SidekiqUniqueJobs::UniqueArgs.digest(@item)
57
+ private
58
+
59
+ # This is safe as the base_lock always creates a new digest
60
+ # The append there for needs to be done every time
61
+ def append_unique_key_suffix
62
+ return if (lock_digest = item[LOCK_DIGEST]).end_with?(RUN_SUFFIX)
63
+
64
+ item[LOCK_DIGEST] = lock_digest + RUN_SUFFIX
47
65
  end
48
66
  end
49
67
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ class Lock
5
+ # Locks jobs while executing
6
+ # Locks from the server process
7
+ # Unlocks after the server is done processing
8
+ #
9
+ # See {#lock} for more information about the client.
10
+ # See {#execute} for more information about the server
11
+ #
12
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
13
+ class WhileExecutingReject < WhileExecuting
14
+ # Overridden with a forced {OnConflict::Reject} strategy
15
+ # @return [OnConflict::Reject] a reject strategy
16
+ def server_strategy
17
+ @server_strategy ||= OnConflict.find_strategy(:reject).new(item, redis_pool)
18
+ end
19
+ end
20
+ end
21
+ end