From 6dd7f00f90086d2ffbbf9e0e082732ae79673804 Mon Sep 17 00:00:00 2001 From: Mika Hel Date: Fri, 8 Feb 2019 20:51:51 +0100 Subject: [PATCH] Various upgrades (#366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Various upgrades - Tweak codeclimate - Change to double quotes - Adds changelog rake task/gem - Adds yard configuration * Tweak the newly added * Update changelog * Add docs * Prefer double quotes * Prefer automatic TOC * Remove docs folder * Enforce some more rubocop validations * Separate requires and module definition * Configure rubocop-rspec * Strip trailing whitespace in markdown * Update tools * Ignore doc folder * Refresh README * Trigger travis * Require spec_helper * Move incompatible gems to gemfile * Refresh changelog * Travis doesn't load .rspec * Remove awesome print * Update gemfiles * Exclude more paths from validation * Rubo👮 --- .codeclimate.yml | 23 +- .csslintrc | 2 - .dockerignore | 4 - .editorconfig | 2 +- .eslintignore | 1 - .eslintrc | 213 ----- .gitignore | 33 +- .mdlrc | 1 + .reek.yml | 1 + .rspec | 2 +- .rubocop.yml | 88 +- .travis.yml | 21 +- .yardopts | 8 +- CHANGELOG.md | 864 ++++++++++++++---- Gemfile | 42 +- Guardfile | 29 - README.md | 142 +-- Rakefile | 27 +- bin/bench | 10 +- bin/uniquejobs | 4 +- examples/custom_queue_job.rb | 2 +- .../custom_queue_job_with_filter_method.rb | 2 +- examples/custom_queue_job_with_filter_proc.rb | 4 +- examples/my_unique_job_with_filter_method.rb | 2 +- examples/my_unique_job_with_filter_proc.rb | 2 +- examples/unique_job_with_filter_method.rb | 2 +- gemfiles/sidekiq_4.0.gemfile | 34 +- gemfiles/sidekiq_4.1.gemfile | 34 +- gemfiles/sidekiq_4.2.gemfile | 34 +- gemfiles/sidekiq_5.0.gemfile | 34 +- gemfiles/sidekiq_5.1.gemfile | 34 +- gemfiles/sidekiq_5.2.gemfile | 34 +- gemfiles/sidekiq_develop.gemfile | 34 +- lib/sidekiq-unique-jobs.rb | 2 +- lib/sidekiq_unique_jobs.rb | 141 +-- lib/sidekiq_unique_jobs/cli.rb | 25 +- lib/sidekiq_unique_jobs/client/middleware.rb | 2 +- lib/sidekiq_unique_jobs/constants.rb | 45 +- lib/sidekiq_unique_jobs/digests.rb | 9 +- lib/sidekiq_unique_jobs/lock/base_lock.rb | 6 +- .../lock/until_executed.rb | 2 +- .../lock/while_executing.rb | 2 +- lib/sidekiq_unique_jobs/locksmith.rb | 8 +- lib/sidekiq_unique_jobs/logging.rb | 2 +- lib/sidekiq_unique_jobs/middleware.rb | 13 +- lib/sidekiq_unique_jobs/normalizer.rb | 2 +- lib/sidekiq_unique_jobs/on_conflict.rb | 19 +- lib/sidekiq_unique_jobs/on_conflict/raise.rb | 2 +- lib/sidekiq_unique_jobs/on_conflict/reject.rb | 6 +- .../on_conflict/strategy.rb | 2 +- .../options_with_fallback.rb | 2 +- lib/sidekiq_unique_jobs/scripts.rb | 10 +- lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb | 2 +- .../sidekiq_unique_jobs.rb | 75 ++ lib/sidekiq_unique_jobs/testing.rb | 6 +- lib/sidekiq_unique_jobs/timeout.rb | 2 +- lib/sidekiq_unique_jobs/unique_args.rb | 4 +- lib/sidekiq_unique_jobs/util.rb | 6 +- lib/sidekiq_unique_jobs/version.rb | 2 +- lib/sidekiq_unique_jobs/web.rb | 16 +- lib/sidekiq_unique_jobs/web/helpers.rb | 4 +- lib/tasks/changelog.rake | 23 + rails_example/Gemfile | 40 +- rails_example/Rakefile | 2 +- rails_example/bin/bundle | 4 +- rails_example/bin/check_or_setup_db | 24 +- rails_example/bin/rails | 6 +- rails_example/bin/rake | 4 +- rails_example/bin/setup | 16 +- rails_example/bin/update | 16 +- rails_example/spec/factories/posts.rb | 8 +- rails_example/spec/spec_helper.rb | 2 +- sidekiq-unique-jobs.gemspec | 58 +- spec/examples/another_unique_job_spec.rb | 15 +- spec/examples/custom_queue_job_spec.rb | 11 +- ...ustom_queue_job_with_filter_method_spec.rb | 15 +- .../custom_queue_job_with_filter_proc_spec.rb | 17 +- spec/examples/expiring_job_spec.rb | 71 +- spec/examples/inline_worker_spec.rb | 15 +- spec/examples/just_a_worker_spec.rb | 15 +- spec/examples/long_running_job_spec.rb | 15 +- spec/examples/main_job_spec.rb | 17 +- spec/examples/my_job_spec.rb | 15 +- spec/examples/my_unique_job_spec.rb | 63 +- .../my_unique_job_with_filter_method_spec.rb | 25 +- .../my_unique_job_with_filter_proc_spec.rb | 23 +- spec/examples/notify_worker_spec.rb | 13 +- spec/examples/plain_class_spec.rb | 15 +- spec/examples/simple_worker_spec.rb | 23 +- spec/examples/spawn_simple_worker_spec.rb | 23 +- spec/examples/test_class_spec.rb | 9 +- .../unique_across_workers_job_spec.rb | 13 +- .../unique_job_on_conflict_raise_spec.rb | 17 +- .../unique_job_on_conflict_reject_spec.rb | 17 +- .../unique_job_on_conflict_reschedule_spec.rb | 17 +- .../unique_job_with_nil_unique_args_spec.rb | 23 +- ...que_job_with_no_unique_args_method_spec.rb | 17 +- ..._job_without_unique_args_parameter_spec.rb | 17 +- .../examples/unique_on_all_queues_job_spec.rb | 13 +- .../until_and_while_executing_job_spec.rb | 13 +- spec/examples/until_executed2_job_spec.rb | 17 +- spec/examples/until_executed_job_spec.rb | 19 +- spec/examples/until_executing_job_spec.rb | 13 +- spec/examples/until_expired_job_spec.rb | 17 +- .../examples/until_global_expired_job_spec.rb | 13 +- spec/examples/while_executing_job_spec.rb | 23 +- spec/examples/without_argument_job_spec.rb | 13 +- spec/integration/sidekiq/retry_set_spec.rb | 49 +- .../client/middleware_spec.rb | 146 +-- .../sidekiq_unique_jobs/legacy_lock_spec.rb | 87 +- .../lock/until_and_while_executing_spec.rb | 35 +- .../lock/until_executed_spec.rb | 57 +- .../lock/until_executing_spec.rb | 55 +- .../lock/until_expired_spec.rb | 45 +- .../lock/while_executing_reject_spec.rb | 49 +- .../lock/while_executing_spec.rb | 41 +- .../sidekiq_unique_jobs/locksmith_spec.rb | 85 +- .../until_and_while_executing_spec.rb | 54 +- .../server/middleware_spec.rb | 31 +- .../sidekiq_unique_jobs/web_spec.rb | 31 +- spec/spec_helper.rb | 42 +- spec/support/matchers/redis_matchers.rb | 6 +- spec/support/retry.rb | 2 +- spec/support/ruby_meta.rb | 2 +- .../shared_examples/a_lockable_lock.rb | 32 +- .../shared_examples/a_performing_worker.rb | 13 +- .../an_executing_lock_with_error_handling.rb | 8 +- .../shared_examples/sidekiq_with_options.rb | 2 +- .../with_a_stubbed_locksmith.rb | 2 +- spec/support/sidekiq_helpers.rb | 14 +- spec/support/sidekiq_meta.rb | 4 +- spec/support/version_check.rb | 4 +- spec/unit/sidekiq_unique_jobs/cli_spec.rb | 62 +- .../client/middleware_spec.rb | 24 +- .../unit/sidekiq_unique_jobs/core_ext_spec.rb | 23 +- spec/unit/sidekiq_unique_jobs/digests_spec.rb | 25 +- .../lock/base_lock_spec.rb | 67 +- .../lock/until_and_while_executing_spec.rb | 27 +- .../lock/until_executed_spec.rb | 39 +- .../lock/until_executing_spec.rb | 15 +- .../lock/until_expired_spec.rb | 23 +- .../lock/while_executing_reject_spec.rb | 27 +- .../lock/while_executing_spec.rb | 25 +- .../sidekiq_unique_jobs/middleware_spec.rb | 67 +- .../sidekiq_unique_jobs/normalizer_spec.rb | 9 +- .../on_conflict/log_spec.rb | 13 +- .../on_conflict/raise_spec.rb | 13 +- .../on_conflict/reject_spec.rb | 93 +- .../on_conflict/replace_spec.rb | 43 +- .../on_conflict/reschedule_spec.rb | 15 +- .../on_conflict/strategy_spec.rb | 17 +- .../sidekiq_unique_jobs/on_conflict_spec.rb | 5 +- .../options_with_fallback_spec.rb | 85 +- spec/unit/sidekiq_unique_jobs/scripts_spec.rb | 18 +- .../server/middleware_spec.rb | 20 +- .../sidekiq_unique_jobs/sidekiq/api_spec.rb | 91 ++ .../sidekiq_unique_ext_spec.rb | 92 -- .../sidekiq_worker_methods_spec.rb | 27 +- .../timeout/calculator_spec.rb | 19 +- .../sidekiq_unique_jobs/unique_args_spec.rb | 119 +-- .../sidekiq_unique_jobs/unlockable_spec.rb | 13 +- spec/unit/sidekiq_unique_jobs/util_spec.rb | 82 +- spec/unit/sidekiq_unique_jobs_spec.rb | 39 +- update_docs.sh | 33 + 164 files changed, 2844 insertions(+), 2373 deletions(-) delete mode 100644 .csslintrc delete mode 100644 .dockerignore delete mode 100644 .eslintignore delete mode 100644 .eslintrc create mode 100644 .mdlrc create mode 100644 lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb create mode 100644 lib/tasks/changelog.rake create mode 100644 spec/unit/sidekiq_unique_jobs/sidekiq/api_spec.rb delete mode 100644 spec/unit/sidekiq_unique_jobs/sidekiq_unique_ext_spec.rb create mode 100755 update_docs.sh diff --git a/.codeclimate.yml b/.codeclimate.yml index 0d4f28a2a..b4ee78655 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,17 +1,15 @@ --- version: '2' plugins: - bundler-audit: - enabled: false duplication: enabled: true config: languages: - ruby - flog: - enabled: true fixme: enabled: true + flog: + enabled: true markdownlint: enabled: true reek: @@ -20,16 +18,15 @@ plugins: file: .reek.yml rubocop: enabled: true - channel: rubocop-0-57 + channel: rubocop-0-63 config: file: .rubocop.yml + exclude_patterns: - - Gemfile + - "Gemfile" - "*.gemspec" - - Appraisals - - spec/**/*.rb - - gemfiles/**/* - - rails_example/**/* - - redis/**/* - - tmp/**/* - + - "Appraisals" + - "gemfiles/" + - "rails_example/" + - "redis/" + - "tmp/" diff --git a/.csslintrc b/.csslintrc deleted file mode 100644 index aacba956e..000000000 --- a/.csslintrc +++ /dev/null @@ -1,2 +0,0 @@ ---exclude-exts=.min.css ---ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 27f1d9cc0..000000000 --- a/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -.dockerignore -.byebug_history -log/* -tmp/* diff --git a/.editorconfig b/.editorconfig index aaeaf0ab6..174dec6ed 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,4 +11,4 @@ indent_style = space indent_size = 2 [*.{md,slim,haml}] -trim_trailing_whitespace = false +trim_trailing_whitespace = true diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 96212a359..000000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -**/*{.,-}min.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 9faa37508..000000000 --- a/.eslintrc +++ /dev/null @@ -1,213 +0,0 @@ -ecmaFeatures: - modules: true - jsx: true - -env: - amd: true - browser: true - es6: true - jquery: true - node: true - -# http://eslint.org/docs/rules/ -rules: - # Possible Errors - comma-dangle: [2, never] - no-cond-assign: 2 - no-console: 0 - no-constant-condition: 2 - no-control-regex: 2 - no-debugger: 2 - no-dupe-args: 2 - no-dupe-keys: 2 - no-duplicate-case: 2 - no-empty: 2 - no-empty-character-class: 2 - no-ex-assign: 2 - no-extra-boolean-cast: 2 - no-extra-parens: 0 - no-extra-semi: 2 - no-func-assign: 2 - no-inner-declarations: [2, functions] - no-invalid-regexp: 2 - no-irregular-whitespace: 2 - no-negated-in-lhs: 2 - no-obj-calls: 2 - no-regex-spaces: 2 - no-sparse-arrays: 2 - no-unexpected-multiline: 2 - no-unreachable: 2 - use-isnan: 2 - valid-jsdoc: 0 - valid-typeof: 2 - - # Best Practices - accessor-pairs: 2 - block-scoped-var: 0 - complexity: [2, 6] - consistent-return: 0 - curly: 0 - default-case: 0 - dot-location: 0 - dot-notation: 0 - eqeqeq: 2 - guard-for-in: 2 - no-alert: 2 - no-caller: 2 - no-case-declarations: 2 - no-div-regex: 2 - no-else-return: 0 - no-empty-label: 2 - no-empty-pattern: 2 - no-eq-null: 2 - no-eval: 2 - no-extend-native: 2 - no-extra-bind: 2 - no-fallthrough: 2 - no-floating-decimal: 0 - no-implicit-coercion: 0 - no-implied-eval: 2 - no-invalid-this: 0 - no-iterator: 2 - no-labels: 0 - no-lone-blocks: 2 - no-loop-func: 2 - no-magic-number: 0 - no-multi-spaces: 0 - no-multi-str: 0 - no-native-reassign: 2 - no-new-func: 2 - no-new-wrappers: 2 - no-new: 2 - no-octal-escape: 2 - no-octal: 2 - no-proto: 2 - no-redeclare: 2 - no-return-assign: 2 - no-script-url: 2 - no-self-compare: 2 - no-sequences: 0 - no-throw-literal: 0 - no-unused-expressions: 2 - no-useless-call: 2 - no-useless-concat: 2 - no-void: 2 - no-warning-comments: 0 - no-with: 2 - radix: 2 - vars-on-top: 0 - wrap-iife: 2 - yoda: 0 - - # Strict - strict: 0 - - # Variables - init-declarations: 0 - no-catch-shadow: 2 - no-delete-var: 2 - no-label-var: 2 - no-shadow-restricted-names: 2 - no-shadow: 0 - no-undef-init: 2 - no-undef: 0 - no-undefined: 0 - no-unused-vars: 0 - no-use-before-define: 0 - - # Node.js and CommonJS - callback-return: 2 - global-require: 2 - handle-callback-err: 2 - no-mixed-requires: 0 - no-new-require: 0 - no-path-concat: 2 - no-process-exit: 2 - no-restricted-modules: 0 - no-sync: 0 - - # Stylistic Issues - array-bracket-spacing: 0 - block-spacing: 0 - brace-style: 0 - camelcase: 0 - comma-spacing: 0 - comma-style: 0 - computed-property-spacing: 0 - consistent-this: 0 - eol-last: 0 - func-names: 0 - func-style: 0 - id-length: 0 - id-match: 0 - indent: 0 - jsx-quotes: 0 - key-spacing: 0 - linebreak-style: 0 - lines-around-comment: 0 - max-depth: 0 - max-len: 0 - max-nested-callbacks: 0 - max-params: 0 - max-statements: [2, 30] - new-cap: 0 - new-parens: 0 - newline-after-var: 0 - no-array-constructor: 0 - no-bitwise: 0 - no-continue: 0 - no-inline-comments: 0 - no-lonely-if: 0 - no-mixed-spaces-and-tabs: 0 - no-multiple-empty-lines: 0 - no-negated-condition: 0 - no-nested-ternary: 0 - no-new-object: 0 - no-plusplus: 0 - no-restricted-syntax: 0 - no-spaced-func: 0 - no-ternary: 0 - no-trailing-spaces: 0 - no-underscore-dangle: 0 - no-unneeded-ternary: 0 - object-curly-spacing: 0 - one-var: 0 - operator-assignment: 0 - operator-linebreak: 0 - padded-blocks: 0 - quote-props: 0 - quotes: 0 - require-jsdoc: 0 - semi-spacing: 0 - semi: 0 - sort-vars: 0 - space-after-keywords: 0 - space-before-blocks: 0 - space-before-function-paren: 0 - space-before-keywords: 0 - space-in-parens: 0 - space-infix-ops: 0 - space-return-throw-case: 0 - space-unary-ops: 0 - spaced-comment: 0 - wrap-regex: 0 - - # ECMAScript 6 - arrow-body-style: 0 - arrow-parens: 0 - arrow-spacing: 0 - constructor-super: 0 - generator-star-spacing: 0 - no-arrow-condition: 0 - no-class-assign: 0 - no-const-assign: 0 - no-dupe-class-members: 0 - no-this-before-super: 0 - no-var: 0 - object-shorthand: 0 - prefer-arrow-callback: 0 - prefer-const: 0 - prefer-reflect: 0 - prefer-spread: 0 - prefer-template: 0 - require-yield: 0 diff --git a/.gitignore b/.gitignore index b88ffac75..142d87979 100644 --- a/.gitignore +++ b/.gitignore @@ -1,28 +1,17 @@ - *.gem - +*.sublime-* +*.sw? .DS_Store - -Gemfile.lock - -.ruby-version .idea/ -gemfiles/*.lock -*.sw? -coverage/ -tmp/ -rails_example/spec/examples.txt - -*.sublime-* - -/sidekiq/ - .rspec_status - -/gemfiles/.bundle/ - +.ruby-version /.byebug_history - /.yardoc/ - -/spec/examples.txt +/doc*/ +/gemfiles/.bundle/ +/sidekiq/ +coverage/ +Gemfile.lock +gemfiles/*.lock +rails_example/spec/examples.txt +tmp/ diff --git a/.mdlrc b/.mdlrc new file mode 100644 index 000000000..b7e08259a --- /dev/null +++ b/.mdlrc @@ -0,0 +1 @@ +rules "~MD013" diff --git a/.reek.yml b/.reek.yml index 4856aa0e3..f136fb4c2 100644 --- a/.reek.yml +++ b/.reek.yml @@ -6,6 +6,7 @@ exclude_paths: - tmp - gemfiles - examples + - vendor/bundle detectors: DuplicateMethodCall: exclude: diff --git a/.rspec b/.rspec index 09127182c..83e16f804 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1,2 @@ --color ---order random +--require spec_helper diff --git a/.rubocop.yml b/.rubocop.yml index 7410c18fe..ece036a48 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,15 +1,28 @@ -require: rubocop-rspec +require: + - rubocop-rspec + +inherit_mode: + merge: + - Exclude + AllCops: + TargetRubyVersion: 2.3 Include: - - '**/Rakefile' - - 'lib/**/*.rb' - - 'bin/**/*.rb' - - 'spec/**/*.rb' - - 'examples/**/*.rb' + - "**/Rakefile" + - "**/Gemfile" + - "*.gemspec" + - "lib/**/*.rb" + - "bin/**/*.rb" + - "spec/**/*.rb" + - "examples/**/*.rb" Exclude: - - 'Gemfile.lock' - - 'gemfiles/**/*' - TargetRubyVersion: 2.3 + - "Gemfile.lock" + - "**/*.erb" + - "gemfiles/**/*" + +Lint/AmbiguousBlockAssociation: + Exclude: + - "spec/**/*" Lint/HandleExceptions: Enabled: true @@ -32,7 +45,10 @@ Metrics/MethodLength: Metrics/BlockLength: Enabled: true Exclude: - - '**/spec/**/*.rb' + - "**/spec/**/*.rb" + - "**/*.rake" + - "Rakefile" + - "*.gemspec" Metrics/PerceivedComplexity: Max: 8 @@ -46,17 +62,19 @@ Naming/ConstantName: Naming/FileName: Enabled: true Exclude: - - 'lib/sidekiq-unique-jobs.rb' - - '**/Gemfile' - - '**/Appraisals' - - '**/*.gemspec' + - lib/sidekiq-unique-jobs.rb Naming/UncommunicativeMethodParamName: AllowedNames: - ex +RSpec/AlignLeftLetBrace: + Enabled: true + RSpec/DescribeClass: - Enabled: false + Exclude: + - spec/unit/sidekiq_unique_jobs/sidekiq/api_spec.rb + - spec/unit/sidekiq_unique_jobs/core_ext_spec.rb RSpec/ExampleLength: Enabled: false @@ -65,13 +83,14 @@ RSpec/ExpectActual: Enabled: false RSpec/ExpectChange: - Enabled: false - -RSpec/ExpectInHook: - Enabled: false + Exclude: + - spec/integration/sidekiq_unique_jobs/lock/**/*_spec.rb +RSpec/FilePath: + Enabled: true RSpec/MessageSpies: - Enabled: false + Exclude: + - spec/unit/sidekiq_unique_jobs/scripts_spec.rb RSpec/MultipleExpectations: Enabled: false @@ -81,29 +100,38 @@ RSpec/NestedGroups: Enabled: true RSpec/RepeatedExample: - Enabled: false - -Style/FrozenStringLiteralComment: - Enabled: true + Exclude: + - spec/unit/sidekiq_unique_jobs/unique_args_spec.rb Style/Documentation: - Enabled: false + Enabled: true + Exclude: + - "examples/**/*.rb" + - "rails_example/**/*.rb" + - "bin/**/*.rb" + - "lib/sidekiq_unique_jobs/testing.rb" + - "lib/sidekiq_unique_jobs/core_ext.rb" + - "lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb" + - "lib/sidekiq_unique_jobs/web/**/*" + - "lib/sidekiq_unique_jobs/on_conflict.rb" + - "lib/sidekiq_unique_jobs/timeout.rb" -Style/SignalException: - EnforcedStyle: only_fail - Enabled: false +Style/FrozenStringLiteralComment: + Enabled: true Style/GlobalVars: Enabled: true +Style/ModuleFunction: + Enabled: false + Style/StringLiterals: Enabled: true - EnforcedStyle: single_quotes + EnforcedStyle: double_quotes ConsistentQuotesInMultiline: true Style/StringLiteralsInInterpolation: Enabled: true - EnforcedStyle: single_quotes Style/SymbolArray: Enabled: true diff --git a/.travis.yml b/.travis.yml index b05621720..b20423229 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,26 +12,33 @@ services: - redis-server before_install: + - gem install bundler -v 2.0.1 - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter + before_script: - - ./cc-test-reporter before-build + - if [[ "${COV}" = "true" ]]; then ./cc-test-reporter before-build; fi; + script: - if [[ "${COV}" = "true" ]]; then bundle exec rubocop -P; fi; - - bundle exec rspec + - bundle exec rspec --require spec_helper + after_script: - if [[ "${COV}" = "true" ]]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi; + rvm: - - 2.5.1 - - 2.4.2 - - 2.3.2 - - jruby-9.2.0.0 + - 2.6.1 + - 2.4.5 + - 2.3.8 + - jruby-9.2.5.0 + matrix: fast_finish: true include: - - rvm: 2.5.1 + - rvm: 2.5.3 gemfile: gemfiles/sidekiq_develop.gemfile env: COV=true + gemfile: - gemfiles/sidekiq_develop.gemfile - gemfiles/sidekiq_4.0.gemfile diff --git a/.yardopts b/.yardopts index f35bd1d7e..841e11a47 100644 --- a/.yardopts +++ b/.yardopts @@ -1,7 +1 @@ - --no-private - --exclude lib/sidekiq_unique_jobs/testing.rb - --exclude lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb - --exclude lib/sidekiq_unique_jobs/middleware.rb - --exclude lib/sidekiq_unique_jobs/core_ext.rb - --exclude lib/sidekiq_unique_jobs/cli.rb - +--no-private --output-dir docs lib/**/*.rb --markup-provider=redcarpet --markup=markdown - README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 39a632ff5..4a7d54e0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,252 +1,796 @@ -## v6.0.8 +# Change Log -- Expire available keys after unlocking ([caused by #352](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/352)) +## [v6.0.8](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.8) (2019-01-10) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.7...v6.0.8) -## v6.0.7 +**Fixed bugs:** -- Fix a bug leaving jobs locked ([#352](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/352)) +- Close \#359 [\#364](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/364) ([mhenrixon](https://github.com/mhenrixon)) -## v6.0.6 +**Closed issues:** -- Fixes a bug with the command line utility ([#321](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/321)) -- Internal refactoring to improve performance ([#318](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/318)) -- Adds coverage for retrying jobs +- Automatic unlock of jobs [\#362](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/362) +- \(6.0.7\) `uniquejobs:{digest}:AVAILABLE` keys never expire [\#359](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/359) +- Strange behavior using strategy "reject" with "until\_executed" [\#358](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/358) +- Pinpointing issues with unique digests not being removed [\#353](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/353) -## v6.0.5 +**Merged pull requests:** -- Fixes a bug with keys not being deleted ([#317](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/317)) +- update changelog [\#356](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/356) ([camallen](https://github.com/camallen)) -## v6.0.4 +## [v6.0.7](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.7) (2018-11-29) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.11...v6.0.7) -- Prevent locks from stealing each other (#316) +**Fixed bugs:** -## v6.0.3 +- Version 5: Job ID Hash Entries Not Removed if Unique Key Expires [\#346](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/346) +- Move the lpush last [\#354](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/354) ([mhenrixon](https://github.com/mhenrixon)) -- Fixes a few hickups (#315) +**Closed issues:** -## v6.0.2 +- First job never unlocks the lock / Endless waiting [\#352](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/352) +- Version 5&6: uniqueness not respected for Job without params [\#349](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/349) -- Fixes sidekiq web pagination of unique digests -- Fixes lock_expiration usage (Lua doesn't support expire after persisting a key) +## [v5.0.11](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.11) (2018-11-19) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.6...v5.0.11) -## v6.0.1 +**Implemented enhancements:** -- Remove unused method that causes conflict with sidekiq/web +- More integration tests [\#329](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/329) ([mhenrixon](https://github.com/mhenrixon)) -## v6.0.0 +**Fixed bugs:** -- Complete rewrite of the locking mechanism -- Improved README -- Improved reliability -- Improved coverage -- Removed a ton of default configuration -- Removed support for ActiveJob -- Added WhileExecutingReject `unique: :while_executing_reject` -- Renamed `UntilTimeout` to `UntilExpired` -- Removed concurrency for now (a0cff5bc42edbe7190d6ede7e7f845074d2d7af6) -- Improved integration testing for locks -- Totally delete the hash that was growing out of proportion -- Adds a sidekiq web extension for viewing and deleting unique digests -- Renamed the configuration `unique:` to `lock:` (still backwards compatible) -- Added some very simplistic conflict strategies. +- Always Remove Job ID from uniquejobs Hash [\#347](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/347) ([chadrschroeder](https://github.com/chadrschroeder)) +- Convert expiration time to integer [\#330](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/330) ([dareddov](https://github.com/dareddov)) -## v5.1.0 +**Closed issues:** -- Refactoring the runtime locks (WhileExecuting) +- concurrent-ruby 1.1.1 is causing this gem to break [\#340](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/340) +- lock remains after job not properly finish [\#339](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/339) +- Using a different Redis instance [\#337](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/337) +- Using :until\_and\_while\_executing not yielding expected results [\#336](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/336) +- "payload is not unique", but cannot find digest or scheduled job [\#335](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/335) +- Confused with UntilExecuted documenation [\#326](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/326) +- Job never requeued after raising unhandled error with until\_and\_while\_executing? [\#322](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/322) -## v5.0.10 +**Merged pull requests:** -- Cleans up test setup and make tests more readable -- Allow raising all errors -- Log previously hidden errors -- Revert the changes of v5.0.5 (8a4b7648b8b0ee5d7dc1f5f5a036f41d52ad9a42) -- Allow name errors in unique args method to be raised +- Do not build keys on lua scripts [\#348](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/348) ([pacoguzman](https://github.com/pacoguzman)) +- fix CHANGELOG syntax [\#344](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/344) ([timoschilling](https://github.com/timoschilling)) +- Define Config class inside SidekiqUniqueJobs module [\#343](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/343) ([Slike9](https://github.com/Slike9)) +- fix readme testing section [\#333](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/333) ([edmartins](https://github.com/edmartins)) +- Fix typo in documentation \[ci-skip\] [\#327](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/327) ([mhenrixon](https://github.com/mhenrixon)) -## v5.0.9 -- [#229](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/#229) Use HSCAN for expiring keys -- [#232](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/#232) Fix testing helper +## [v6.0.6](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.6) (2018-08-09) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.5...v6.0.6) -## v5.0.8 -- Fixes [#220](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/220) +**Implemented enhancements:** -## v5.0.7 -- Fixes [#218](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/218) +- Adds coverage for job retries [\#321](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/321) ([mhenrixon](https://github.com/mhenrixon)) +- Internal refactoring [\#318](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/318) ([mhenrixon](https://github.com/mhenrixon)) -## v5.0.6 -- Allow across worker uniquenes: See https://github.com/mhenrixon/sidekiq-unique-jobs/blob/master/spec/jobs/unique_acrosss_workers_job.rb for information +**Closed issues:** -## v5.0.5 -- Use a class level mutex for `while_executing` +- Unique UntilExecuted not working while the job is executing? [\#319](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/319) -## v5.0.4 -- Fixes a problem with installing the gem +## [v6.0.5](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.5) (2018-08-07) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.4...v6.0.5) -## v5.0.3 -- Removes test files and appraisals and such from the released gem version to speed up gem installs +**Fixed bugs:** -## v5.0.2 -- Added more helpful debug, warning and error messages for failures to collect unique arghuments +- Unlock instead of signal [\#317](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/317) ([mhenrixon](https://github.com/mhenrixon)) -## v5.0.1 +**Closed issues:** -- Added a command line util for cleaning out expired keys -- Use `SidekiqUniqueJobs.logger` instead of spreading out `Sidekiq.logger` everywhere. +- Why is lock\_timeout: nil VERY DANGEROUS? [\#313](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/313) -## v5.0.0 +## [v6.0.4](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.4) (2018-08-02) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.3...v6.0.4) -- Only support Sidekiq >= 4 -- Removed overrides and support for older Sidekiq testing -- Added coverage +**Fixed bugs:** -## v4.0.18 +- Fix the broken expiration [\#316](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/316) ([mhenrixon](https://github.com/mhenrixon)) -- Allow mock_redis to be used over redis -- Fixes some locking inconsistencies +**Closed issues:** -## v4.0.17 +- Question about until\_timeout with 6.0.0 [\#303](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/303) -- Always release lock in the lua script `release_lock.lua` and return success [#169](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/169) +## [v6.0.3](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.3) (2018-08-02) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.2...v6.0.3) -## v4.0.16 +**Fixed bugs:** -- Allow run & queue lock timeout (expiration) to be different [#164](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/164) -- Fix a bug with loading sidekiq test overrides ([#167](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/167) +- Enable replace strategy [\#315](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/315) ([mhenrixon](https://github.com/mhenrixon)) -## v4.0.15 +**Closed issues:** -- Close [#156](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/156) -- Close [#158](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/158) -- Style fixes and some minor adjustments to the console/cmd line app +- Sidekiq Web Pagination Broken [\#309](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/309) -## v4.0.13 +**Merged pull requests:** -- Allow deleting locks by jid +- Correct documentation typo \[ci skip\] [\#312](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/312) ([mhenrixon](https://github.com/mhenrixon)) -## v4.0.12 +## [v6.0.2](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.2) (2018-08-01) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.1...v6.0.2) -- Allow jobs to be pushed to processing -- Close [#150](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/150) -- Close [#151](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/151) -- Close [#146](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/146) -- Close [#136](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/136) -- Close [#133](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/133) +**Fixed bugs:** -## v4.0.11 +- Not unlocking automatically \(version 6.0.0rc5\) [\#293](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/293) +- Bug fixes [\#310](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/310) ([mhenrixon](https://github.com/mhenrixon)) -- Always load forwardable [#152](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/152#issuecomment-164199978) +## [v6.0.1](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.1) (2018-07-31) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0...v6.0.1) -## v4.0.10 +**Fixed bugs:** -- Fix [#152](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/152) -- Minor improvement to internal esthetics +- :until\_executed is throwing errors and not requeuing the job. [\#256](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/256) +- Remove unused method [\#307](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/307) ([mhenrixon](https://github.com/mhenrixon)) -## v4.0.9 +**Closed issues:** -- Add command line and console extensions for removal of unique jobs (c292d87) +- ArgumentError: sidekiq\_unique\_jobs/web breaks sidekiq Retries page [\#306](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/306) +- If the job dies, it doesn't remove the lock [\#304](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/304) -## v4.0.8 +**Merged pull requests:** -- Use unique arguments for the `WhileExecuting` lock ([#127](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/127) -- Delicensed code ([#132](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/132) -- Fix queuing unique jobs ([#138](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/138) +- Dead jobs [\#308](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/308) ([mhenrixon](https://github.com/mhenrixon)) +- Fix require path for sidekiq\_unique\_jobs/web [\#305](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/305) ([soundasleep](https://github.com/soundasleep)) -## v4.0.7 +## [v6.0.0](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0) (2018-07-27) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.rc8...v6.0.0) -- Use unique arguments for the `WhileExecuting` lock ([#127](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/127) -- See also https://github.com/mhenrixon/sidekiq-unique-jobs/releases/tag/v4.0.7 +## [v6.0.0.rc8](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.rc8) (2018-07-24) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.rc7...v6.0.0.rc8) -## v4.0.6 +**Implemented enhancements:** -- Removes enforced uniqueness for all jobs ([#127](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/127) +- Add RequeueWhileExecuting strategy [\#223](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/223) +- New feature: Replace original job if duplicate is added [\#177](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/177) +- Add a replace strategy for client locks [\#302](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/302) ([mhenrixon](https://github.com/mhenrixon)) -## v4.0.5 +**Merged pull requests:** -- Forces look for `Sidekiq::Testing` in Sidekiq without ancestors #129 +- Add more details about testing uniqueness [\#301](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/301) ([mhenrixon](https://github.com/mhenrixon)) +- Update README.md [\#300](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/300) ([pirj](https://github.com/pirj)) -## v4.0.4 +## [v6.0.0.rc7](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.rc7) (2018-07-23) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.rc6...v6.0.0.rc7) -- Fix usage with active job -- Get rid of unneeded configuration options `unique_args_enabled` (just use whatever unique argument that is configured). +**Implemented enhancements:** -## v4.0.3 +- Sidekiq web [\#297](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/297) ([mhenrixon](https://github.com/mhenrixon)) +- Document code [\#296](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/296) ([mhenrixon](https://github.com/mhenrixon)) +- Rename to `unique:` to `lock:` [\#295](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/295) ([mhenrixon](https://github.com/mhenrixon)) -- Remove `unique_lock` and use `unique: ` to set this like in `unique: :until_timeout` -- Warn when using `unique: true` and suggest to change it to what we need with a fallback. -- Create constants for hash keys to avoid having to fix spelling or for renaming keys only having to be done in one place and avoid having to type .freeze everywhere. -- Move all explicit logic out from the server middle ware and make it just call execute on the instance of the lock class (prepare for allowing custom locking classes to be used). -- Create a new job for scheduling jobs after it started executing but only allow one job to run at the same time. +**Closed issues:** -## v4.0.2 +- Unique Job not work while play with crontab [\#294](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/294) +- Making the GEM compatible with Ruby \< 2.3 [\#291](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/291) -- Fix a problem with an unresolved reference +**Merged pull requests:** -## v4.0.1 +- Adds changelog entry [\#299](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/299) ([mhenrixon](https://github.com/mhenrixon)) +- Fix README [\#298](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/298) ([mhenrixon](https://github.com/mhenrixon)) -- Get rid of development dependency on active support (causing trouble with jruby) +## [v6.0.0.rc6](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.rc6) (2018-07-15) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.rc5...v6.0.0.rc6) -## v4.0.0 +**Fixed bugs:** -- Improved uniqueness handling (complete refactoring, upgrade with caution) -- 100% breaking changes +- Don't unlock when worker raises an error [\#290](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/290) ([mhenrixon](https://github.com/mhenrixon)) -## v3.0.15 +**Closed issues:** -- Jobs only ever unlock themselves now (see #96 & #94 for info) thanks @pik -- Slight refactoring and internal renaming. Shouldn't affect anyone -- Run locks as an alternative when you only need to prevent the same job running twice but want to be able to schedule it multiple times. See #99 (thanks @pik) -- Fixes #90, #92, #93, #97, #98, #100, #101, #105 +- Locking with retries [\#289](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/289) -## v3.0.14 +**Merged pull requests:** -- Improve uniqueness check performance thanks @mpherham -- Remove locks in sidekiq fake testing mode -- Do not unlock jobs when sidekiq is shutting down +- Readme [\#288](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/288) ([mhenrixon](https://github.com/mhenrixon)) -## v3.0.13 +## [v6.0.0.rc5](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.rc5) (2018-06-30) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.rc4...v6.0.0.rc5) -- Improved testing capabilities (testing uniqueness should not work better) -- Configurable logging of duplicate payloads -- Now requires `sidekiq_unique_ext` and `sidekiq/api` by default -- Drop support for MRI 1.9 and sidekiq 2 +**Fixed bugs:** -## v3.0.11 +- bundle exec jobs console does not work [\#253](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/253) +- Rename command line binary [\#287](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/287) ([mhenrixon](https://github.com/mhenrixon)) -- Ensure threadsafety (thanks to adstage-david) +## [v6.0.0.rc4](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.rc4) (2018-06-30) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.rc3...v6.0.0.rc4) -## v3.0.9 -- Fixed that all jobs stopped processing +**Implemented enhancements:** -## v3.0.8 +- Prepare for v6 [\#286](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/286) ([mhenrixon](https://github.com/mhenrixon)) +- Only unlock not delete [\#285](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/285) ([mhenrixon](https://github.com/mhenrixon)) -- Unique extensions for Web GUI by @rickenharp. Uniqueness will now be removed when a job is. +## [v6.0.0.rc3](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.rc3) (2018-06-29) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.rc2...v6.0.0.rc3) -## v3.0.7 +**Fixed bugs:** -- Internal refactoring -- Improved coverage -- Rubocop style validation +- Fix waiting for locks [\#284](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/284) ([mhenrixon](https://github.com/mhenrixon)) -## v3.0.5 +## [v6.0.0.rc2](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.rc2) (2018-06-26) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.rc1...v6.0.0.rc2) -- Fixed the different test modes (major thanks to @salrepe) +**Implemented enhancements:** -## v3.0.2 +- Within tests: workers enqueued in the future don't clear their unique locks after being drained/executed [\#254](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/254) +- Unexpected behavior with until\_executed [\#250](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/250) -- Removed runtime dependency on mock_redis (add `gem 'mock_redis'` to your desired group to use it) +**Fixed bugs:** -## v2.7.0 +- Unique job needs to be unlocked manually? [\#261](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/261) +- Duplicate jobs getting created [\#257](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/257) +- Multiple non-unique jobs with until\_executed? [\#255](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/255) +- :until\_executing not unlocking when starting to run [\#245](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/245) +- Drop jobs hash [\#282](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/282) ([mhenrixon](https://github.com/mhenrixon)) -- Use mock_redis when testing in fake mode -- Replace minitest with rspec -- Add codeclimate badge -- Update travis with redis-server +**Closed issues:** -## v2.6.5 +- Difference between :until\_and\_while\_executing vs :until\_executed is not clear [\#249](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/249) +- Deprecated Documentation [\#246](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/246) +- Are we meant to manually expire the unique jobs hash? [\#234](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/234) +- How :until\_executing works ? Run job only once and discard new jobs while another job is executing [\#226](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/226) -- via @sax - possibility to set which arguments should be counted as unique - https://github.com/form26/sidekiq_unique_jobs/pull/12 -- via @eduardosasso - possibility to set which arguments should be counted as unique - https://github.com/form26/sidekiq_unique_jobs/pull/11 -- via @KensoDev - configuration of default expiration - https://github.com/form26/sidekiq_unique_jobs/pull/9 +**Merged pull requests:** -## v2.1.0 +- Remove some misleading information [\#283](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/283) ([mhenrixon](https://github.com/mhenrixon)) -Extracted the unique jobs portion from sidekiq main repo since @mperham dropped support for it. +## [v6.0.0.rc1](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.rc1) (2018-06-26) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.beta2...v6.0.0.rc1) + +**Implemented enhancements:** + +- Legacy support [\#280](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/280) +- Adds legacy support [\#281](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/281) ([mhenrixon](https://github.com/mhenrixon)) +- Adds guard-reek [\#279](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/279) ([mhenrixon](https://github.com/mhenrixon)) +- Fix UntilExpired [\#278](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/278) ([mhenrixon](https://github.com/mhenrixon)) + +**Fixed bugs:** + +- Fix UntilExpired [\#278](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/278) ([mhenrixon](https://github.com/mhenrixon)) + +## [v6.0.0.beta2](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.beta2) (2018-06-25) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.beta1...v6.0.0.beta2) + +**Implemented enhancements:** + +- Make locks more robust [\#277](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/277) ([mhenrixon](https://github.com/mhenrixon)) +- Rename UntilTimeout -\> UntilExpired [\#276](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/276) ([mhenrixon](https://github.com/mhenrixon)) + +## [v6.0.0.beta1](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.beta1) (2018-06-22) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v6.0.0.beta...v6.0.0.beta1) + +**Implemented enhancements:** + +- Code smells [\#275](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/275) ([mhenrixon](https://github.com/mhenrixon)) +- Reject while scheduling [\#273](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/273) ([mhenrixon](https://github.com/mhenrixon)) +- Improve testing [\#272](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/272) ([mhenrixon](https://github.com/mhenrixon)) + +## [v6.0.0.beta](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v6.0.0.beta) (2018-06-17) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.10...v6.0.0.beta) + +**Implemented enhancements:** + +- Until and while executing [\#271](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/271) ([mhenrixon](https://github.com/mhenrixon)) +- Solidify master [\#270](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/270) ([mhenrixon](https://github.com/mhenrixon)) +- Minor adjustments [\#268](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/268) ([mhenrixon](https://github.com/mhenrixon)) +- Use ruby 2.5.1 [\#267](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/267) ([mhenrixon](https://github.com/mhenrixon)) +- Add explicit concurrent-ruby dependency. [\#265](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/265) ([brettburley](https://github.com/brettburley)) + +**Fixed bugs:** + +- Allow `jobs keys` to default to listing all keys [\#252](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/252) ([soundasleep](https://github.com/soundasleep)) + +**Closed issues:** + +- Incomplete sentence in README [\#264](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/264) +- ActiveJob and Sidekiq::Worker [\#259](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/259) +- ActiveJob and Sidekiq::Worker [\#258](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/258) +- Non-unique jobs can be added even when `sidekiq\_options unique: :until\_executed` [\#251](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/251) +- Trouble with "inline" mode [\#243](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/243) +- Sidekiq::Worker.set not working with sidekiq-unique-jobs [\#242](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/242) +- sidekiq-unique-job with ActiveJob [\#238](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/238) +- Deadlock using :while\_executing? [\#233](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/233) + +**Merged pull requests:** + +- Improve documentation [\#269](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/269) ([mhenrixon](https://github.com/mhenrixon)) +- Remove unnecessary monkey patches for String [\#262](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/262) ([zormandi](https://github.com/zormandi)) +- README \> While Executing: remove unnecessary word [\#260](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/260) ([TimCannady](https://github.com/TimCannady)) +- Don't skip monkeypatches if ActiveSupport present [\#248](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/248) ([dleavitt](https://github.com/dleavitt)) +- Better runtime locks [\#241](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/241) ([mhenrixon](https://github.com/mhenrixon)) + +## [v5.0.10](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.10) (2017-08-19) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.9...v5.0.10) + +**Closed issues:** + +- Version v5.0.5 might have introduced a breaking change in while\_executing and was not documented [\#230](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/230) +- String arguments not seen as unique [\#222](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/222) +- unique\_args method suppresses all `NameError` exceptions [\#219](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/219) + +**Merged pull requests:** + +- Various improvements [\#240](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/240) ([mhenrixon](https://github.com/mhenrixon)) +- Fix: uninitialized constant CustomQueueJob on rspec [\#239](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/239) ([dalpo](https://github.com/dalpo)) + +## [v5.0.9](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.9) (2017-07-06) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.8...v5.0.9) + +**Closed issues:** + +- The work of several unique sidekiq tasks within one queue [\#225](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/225) +- Missing documentation on activejob usage [\#221](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/221) + +**Merged pull requests:** + +- Your testing lib is broken and don't permit to test uniqueness of jobs [\#232](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/232) ([keysen](https://github.com/keysen)) +- Use hscan for Util\#expire [\#229](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/229) ([dmkc](https://github.com/dmkc)) +- Fixed documentation example about unique\_args [\#228](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/228) ([andresakata](https://github.com/andresakata)) +- Fix filename [\#224](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/224) ([ikataitsev](https://github.com/ikataitsev)) + +## [v5.0.8](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.8) (2017-05-03) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.7...v5.0.8) + +**Closed issues:** + +- Using JSON.parse in delete\_by\_value\_ext break compatiblity with other Sidekiq extensions [\#220](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/220) +- Is it possible to get the Job ID of original job? [\#217](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/217) + +## [v5.0.7](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.7) (2017-04-26) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.6...v5.0.7) + +**Closed issues:** + +- Can't delete Sidekiq::Job after 5.0.1 [\#218](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/218) +- Uniqueness across workers [\#210](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/210) + +## [v5.0.6](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.6) (2017-04-23) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.5...v5.0.6) + +**Closed issues:** + +- Different unique arguments depending on lock type [\#203](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/203) +- Strategy until\_and\_while\_executing not working properly [\#199](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/199) +- while\_executing working wrong [\#193](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/193) + +## [v5.0.5](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.5) (2017-04-23) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.4...v5.0.5) + +**Merged pull requests:** + +- Fixed typo on README.md [\#216](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/216) ([jsantos](https://github.com/jsantos)) + +## [v5.0.4](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.4) (2017-04-18) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.3...v5.0.4) + +## [v5.0.3](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.3) (2017-04-18) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.2...v5.0.3) + +## [v5.0.2](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.2) (2017-04-17) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.1...v5.0.2) + +**Closed issues:** + +- Uniqueness should not survive Class.jobs.clear [\#214](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/214) +- when arguments are empty then unique\_args proc/method is not executed [\#201](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/201) + +## [v5.0.1](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.1) (2017-04-16) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v5.0.0...v5.0.1) + +**Closed issues:** + +- Removing "uniquejobs" hash? [\#213](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/213) +- deprecation warnings with redis-namespace 2.0 [\#212](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/212) +- Unclear docs / examples for unique\_args [\#211](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/211) +- Jobs Console fails to launch [\#208](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/208) +- Util.del Redis::CommandError: ERR syntax error [\#207](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/207) +- version 4.0.19 [\#206](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/206) +- Job.delete does not remove lock in all circumstances [\#205](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/205) +- disappearing jobs - known issue in conjunction with other extensions? [\#202](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/202) +- Broken pipe @ io\_write - \ on sidekiq unique jobs [\#198](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/198) +- Doesn't play well with redis-namespace [\#196](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/196) +- SidekiqUniqueJobs::ScriptError [\#192](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/192) + +**Merged pull requests:** + +- Add the possibility to clear the hash [\#215](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/215) ([mhenrixon](https://github.com/mhenrixon)) + +## [v5.0.0](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.0) (2017-04-08) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.18...v5.0.0) + +**Fixed bugs:** + +- Can't enable testing with newer versions of sidekiq [\#175](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/175) +- strange behaviour [\#172](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/172) + +**Closed issues:** + +- Could not find a valid gem 'sidekiq-unique-jobs' \(= 3.0.15\) in any repository [\#197](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/197) +- `uniquejobs` hash doesn't get cleaned up [\#195](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/195) +- Code block under "Finer Control over Uniqueness" in your documentation might have the wrong option specified [\#191](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/191) +- not able to run test without live Redis [\#186](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/186) +- unique while not sucessfully completed? [\#185](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/185) +- Duplicate jobs when using :until\_and\_while\_executing [\#181](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/181) +- unique: :while\_executing doesn't remove lock when the Sidekiq node running the job shuts down and terminates the job prematurely [\#170](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/170) +- :while\_executing appears to be broken [\#159](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/159) +- Using ":until\_executing, :until\_executed, :until\_timeout, :until\_and\_while\_executing" all break Sidekiq::Testing [\#157](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/157) +- Way to remove lock in application code [\#147](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/147) + +**Merged pull requests:** + +- Increase sleep delay in WhileExecuting\#synchronize [\#204](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/204) ([dsander](https://github.com/dsander)) +- Ensure job ID removed from uniquejobs hash [\#200](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/200) ([carlosmartinez](https://github.com/carlosmartinez)) +- unique args need to be an array [\#194](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/194) ([pboling](https://github.com/pboling)) + +## [v4.0.18](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.18) (2016-07-24) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.17...v4.0.18) + +**Closed issues:** + +- ArgumentError: wrong number of arguments \(given 1, expected 2\) [\#190](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/190) +- Should be note on document only works on production mode [\#189](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/189) +- SidekiqUniqueJobs::ScriptError: release\_lock.lua NOSCRIPT No matching script. [\#187](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/187) +- sidekiq-unique-jobs kills sidekiq in production [\#183](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/183) +- Parameters turn into String [\#182](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/182) +- You really helped me today [\#180](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/180) +- 4.0.17 config [\#171](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/171) +- Problem with releasing uniquejobs locks after timeout expires [\#169](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/169) +- NOSCRIPT No matching script. Please use EVAL. [\#168](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/168) +- Broken compatibility with Sidekiq 3.4 [\#140](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/140) + +**Merged pull requests:** + +- missed space [\#188](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/188) ([TheBigSadowski](https://github.com/TheBigSadowski)) +- Convert unless if to just 1 if [\#179](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/179) ([otzy007](https://github.com/otzy007)) +- fix for \#168. Handle the NOSCRIPT by sending the script again [\#178](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/178) ([otzy007](https://github.com/otzy007)) +- Fixed gitter badge link [\#176](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/176) ([andrew](https://github.com/andrew)) + +## [v4.0.17](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.17) (2016-03-02) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.16...v4.0.17) + +**Closed issues:** + +- No place where I can say "Thank you" for all contributors [\#165](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/165) + +## [v4.0.16](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.16) (2016-02-17) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.15...v4.0.16) + +**Merged pull requests:** + +- Fix for sidekiq delete failing for version 3.4.x [\#167](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/167) ([theprogrammerin](https://github.com/theprogrammerin)) +- Run lock timeout configurable [\#164](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/164) ([Slania](https://github.com/Slania)) + +## [v4.0.15](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.15) (2016-02-16) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.13...v4.0.15) + +**Closed issues:** + +- Until timeout question [\#163](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/163) +- Error when run rspec [\#162](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/162) +- Unique job keys never dissapear [\#161](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/161) +- Uniqueness breaks jobs [\#160](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/160) +- Too many open files [\#155](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/155) + +**Merged pull requests:** + +- Add a Gitter chat badge to README.md [\#166](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/166) ([gitter-badger](https://github.com/gitter-badger)) +- Fix test overrides. [\#158](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/158) ([benseligman](https://github.com/benseligman)) +- Remove wrong Server::Middleware\#worker\_class override [\#156](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/156) ([vkuznetsov](https://github.com/vkuznetsov)) + +## [v4.0.13](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.13) (2015-12-16) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.12...v4.0.13) + +**Closed issues:** + +- Seeing this error with latest version 4.0.12 [\#154](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/154) +- Unique job showing weird behavior [\#153](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/153) + +## [v4.0.12](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.12) (2015-12-15) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.11...v4.0.12) + +**Closed issues:** + +- Can't schedule a job from another job [\#151](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/151) +- perform\_in not working in version 4.0.9 [\#150](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/150) +- `unique: until\_and\_while\_executing` not working as expected [\#146](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/146) +- while\_executing still runs duplicate tasks [\#136](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/136) +- Version 4 Upgrade [\#133](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/133) + +## [v4.0.11](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.11) (2015-12-12) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.10...v4.0.11) + +**Closed issues:** + +- Release a new version for Ruby \< 2.1 compatability [\#152](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/152) + +## [v4.0.10](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.10) (2015-12-12) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.9...v4.0.10) + +**Closed issues:** + +- Until Executed is taking waiting for unique\_expiration [\#149](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/149) +- Until Executed vs Unique Until And While Executing is confusing in README [\#148](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/148) +- sidekiq-unique-jobs not enabled from sidekiq workers [\#131](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/131) + +## [v4.0.9](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.9) (2015-11-14) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.8...v4.0.9) + +**Closed issues:** + +- Error when using unique\_args in 4.0.8 [\#145](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/145) +- Ignore lock when jobs spawned from another sidekiq worker [\#142](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/142) +- Two Rails apps on the same server, but only one Sidekiq instances is working correctly [\#141](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/141) +- ActiveRecord::RecordNotDestroyed: Failed to destroy the record [\#139](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/139) + +## [v4.0.8](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.8) (2015-10-31) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.7...v4.0.8) + +**Closed issues:** + +- Jobs not getting queued in v4 [\#138](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/138) +- Unique args being considered? [\#137](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/137) +- No mention how to test in README [\#135](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/135) +- License Difference [\#132](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/132) + +**Merged pull requests:** + +- Calculate worker's unique args when a proc or a symbol is specified [\#143](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/143) ([zeqfreed](https://github.com/zeqfreed)) +- Fix markdown link formatting [\#134](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/134) ([thbar](https://github.com/thbar)) + +## [v4.0.7](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.7) (2015-10-14) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.6...v4.0.7) + +**Closed issues:** + +- docs clarification [\#130](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/130) +- 4.\* is hurting background job workers performance [\#127](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/127) + +## [v4.0.6](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.6) (2015-10-14) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.5...v4.0.6) + +**Closed issues:** + +- NameError: uninitialized constant SidekiqUniqueJobs::RunLockFailed [\#126](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/126) + +## [v4.0.5](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.5) (2015-10-13) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.4...v4.0.5) + +**Closed issues:** + +- Rails + Sidekiq will go bezerk after sidekiq-unique-jobs testing check. [\#128](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/128) +- NoMethodError: undefined method `to\_sym' for true:TrueClass [\#125](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/125) +- Redis::CommandError: ERR unknown command 'eval' [\#124](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/124) + +**Merged pull requests:** + +- Forces to look for testing namespace in Sidekiq and not his ancestors [\#129](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/129) ([antek-drzewiecki](https://github.com/antek-drzewiecki)) +- Fix outdated phrasing and add test coverage to readme [\#123](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/123) ([albertyw](https://github.com/albertyw)) + +## [v4.0.4](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.4) (2015-10-09) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.3...v4.0.4) + +**Closed issues:** + +- Active job with unique args doesn't work [\#120](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/120) +- 4.0.1 =\> job no longer unique [\#117](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/117) +- Update Changelog and Tags [\#115](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/115) + +## [v4.0.3](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.3) (2015-10-08) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.2...v4.0.3) + +**Closed issues:** + +- unique\_unlock\_order - never option [\#122](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/122) +- Run 1 job and queue 1 [\#121](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/121) +- unique\_lock vs unique\_locks typo [\#119](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/119) +- 4.0.2 commited but not released to rubygems? [\#118](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/118) + +## [v4.0.2](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.2) (2015-10-06) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/4.0.1...v4.0.2) + +## [4.0.1](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/4.0.1) (2015-10-06) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v4.0.0...4.0.1) + +**Closed issues:** + +- Don't work with perform\_in [\#114](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/114) +- 3.0.15 apparently breaks inline testing [\#113](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/113) +- sidekiq\_unique record in Redis is not cleaned when foreman process is killed [\#112](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/112) +- Can't ensure unique job simultaneously. [\#111](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/111) +- Job considered as duplicate after completion only in production [\#110](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/110) +- Gem requires Redis 2.6+? [\#109](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/109) +- unable to re-schedule job at specific time [\#108](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/108) +- Documentation Not Clear [\#78](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/78) +- Runtime uniqueness when using :before\_yield as unlock order [\#72](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/72) +- Using with sidekiq delayed extensions [\#45](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/45) + +**Merged pull requests:** + +- Clean up version 4 upgrade instructions [\#116](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/116) ([albertyw](https://github.com/albertyw)) + +## [v4.0.0](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.0) (2015-10-05) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v3.0.11...v4.0.0) + +**Implemented enhancements:** + +- Duplicated Jobs With Nested Sidekiq Workers [\#10](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/10) + +**Closed issues:** + +- 3.0.14 Error: ERR wrong number of arguments for 'set' command \(Redis::CommandError\) [\#104](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/104) +- Testing [\#103](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/103) +- Active Job [\#102](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/102) +- Why is SidekiqUnique behaviour applied to regular Workers? [\#100](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/100) +- Confusing behavior when trying to `\[1,2,3\].each { |n| SomeJob.perform\_in\(n.seconds.from\_now, n\) }` never running, logging as duplicate value [\#98](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/98) +- Scheduled jobs are not unlocked when deleted [\#97](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/97) +- Testing functions should be moved out of production code [\#95](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/95) +- Jobs can unlock mutexes they don't own [\#94](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/94) +- Jobs scheduled in the future are never run [\#93](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/93) +- perform\_at and perform\_async do not unique if perform\_at is in the future. [\#91](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/91) +- Latest release is breaking [\#90](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/90) +- Optimize Redis usage [\#89](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/89) +- Unique jobs sets Sidekiq testing to inline! mode [\#88](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/88) +- Test suite unclear on what happens when duplicate job is attempted [\#84](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/84) +- Change log level to info rather than warn [\#80](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/80) +- Jobs are unlocked if they fail and are retried [\#77](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/77) +- Usage of sidekiq-unique-jobs with activejob [\#76](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/76) +- If a job is deleted from the enqueued list, it's still unique and new jobs can't be added. [\#74](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/74) +- Incorrect README re: uniqueness time? [\#73](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/73) +- Sidekiq::Testing inline detection assumes you're always using inline testing [\#71](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/71) +- unique\_args\_enabled has been deprecated, nothing in readme [\#70](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/70) +- The second job does not run, even if it has different arguments [\#69](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/69) +- Jobs not being executed anymore?? [\#65](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/65) +- mock\_redis and the mess [\#62](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/62) +- What is the exact behavior? [\#47](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/47) +- Throttling jobs [\#39](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/39) +- undefined method `get\_sidekiq\_options' for "MyScheduledWorker":String [\#27](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/27) +- Crash handling [\#14](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/14) +- Missing info from README [\#6](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/6) + +**Merged pull requests:** + +- Allow job with jid matching unique lock to pass unique check [\#105](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/105) ([deltaroe](https://github.com/deltaroe)) +- Prevent Jobs from deleting mutexes they don't own [\#96](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/96) ([pik](https://github.com/pik)) +- Add after unlock hook [\#92](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/92) ([HParker](https://github.com/HParker)) +- Do not unlock on sidekiq shutdown [\#87](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/87) ([deltaroe](https://github.com/deltaroe)) +- Remove no-op code, protect global space from test code [\#86](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/86) ([stevenjonescgm](https://github.com/stevenjonescgm)) +- Remove unique lock when executing and clearing jobs in sidekiq fake mode [\#83](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/83) ([crberube](https://github.com/crberube)) +- Fix tests. Tests with latest sidekiq versions and ruby versions [\#82](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/82) ([simonoff](https://github.com/simonoff)) +- Duplicate Payload logging configuration [\#81](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/81) ([jprincipe](https://github.com/jprincipe)) +- output log if not unique [\#79](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/79) ([sonots](https://github.com/sonots)) +- Checking Sidekiq::Testing.inline? on testing strategy and connector [\#75](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/75) ([Draiken](https://github.com/Draiken)) + +## [v3.0.11](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v3.0.11) (2014-12-15) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v3.0.10...v3.0.11) + +**Closed issues:** + +- ConnectionPool used incorrectly - causes deadlocks [\#66](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/66) +- undefined `configuration` when using .configure [\#64](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/64) + +**Merged pull requests:** + +- Use ConnectionPool blocks to ensure exclusive connection. Closes \#66. [\#67](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/67) ([adstage-david](https://github.com/adstage-david)) + +## [v3.0.10](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v3.0.10) (2014-11-19) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v3.0.9...v3.0.10) + +**Closed issues:** + +- LoadError: cannot load such file -- mock\_redis [\#60](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/60) +- The deprecation message is unclear and unnecessary [\#59](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/59) + +**Merged pull requests:** + +- Added method name to depreciation warning message [\#61](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/61) ([jamesbowles](https://github.com/jamesbowles)) + +## [v3.0.9](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v3.0.9) (2014-11-05) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v3.0.3...v3.0.9) + +**Closed issues:** + +- sidekiq-unique-jobs prevents not unique jobs creation event with sidekiq inline test mode [\#58](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/58) +- mock redis dependency [\#55](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/55) +- Unique key inconsistency between server and client [\#48](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/48) +- Example Test using Sidekiq::Testing.inline [\#44](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/44) +- Will a second job lose if the job is already queued, or is already scheduled? [\#43](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/43) +- Can you update the change log? [\#42](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/42) + +**Merged pull requests:** + +- Refactoring connectors to use them in client and server [\#56](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/56) ([salrepe](https://github.com/salrepe)) +- Fix dependency error in inline testing connector [\#54](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/54) ([salrepe](https://github.com/salrepe)) +- Add extension to Sidekiq API that is uniqueness-aware [\#52](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/52) ([rickenharp](https://github.com/rickenharp)) + +## [v3.0.3](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v3.0.3) (2014-11-03) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v3.0.2...v3.0.3) + +**Closed issues:** + +- is mock\_redis really a runtime dependency? [\#46](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/46) + +**Merged pull requests:** + +- Unlock testing inline jobs like normal ones [\#53](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/53) ([salrepe](https://github.com/salrepe)) +- Declare mock\_redis as development dependency instead of runtime one [\#51](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/51) ([phuongnd08](https://github.com/phuongnd08)) + +## [v3.0.2](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v3.0.2) (2014-06-08) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v3.0.1...v3.0.2) + +**Closed issues:** + +- Add unique job key to the message json [\#40](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/40) + +**Merged pull requests:** + +- Add the unique hash to the message for use by the workers. [\#41](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/41) ([sullimander](https://github.com/sullimander)) + +## [v3.0.1](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v3.0.1) (2014-06-08) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v2.7.0...v3.0.1) + +**Closed issues:** + +- Support for sidekiq 3? [\#34](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/34) +- Short jobs are not unique for the given time window [\#33](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/33) +- Not all sidekiq:sidekiq\_unique keys are removed from Redis [\#31](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/31) +- What does uniqueness mean in case of this gem? [\#30](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/30) +- Server middleware removes payload hash key before expiration [\#26](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/26) +- Lock remains when running with Sidekiq::Testing.inline! [\#23](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/23) +- What is the use case for the uniqueness window? [\#22](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/22) +- clarification on unique\_args [\#20](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/20) +- payload\_hash staying around [\#13](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/13) + +**Merged pull requests:** + +- Fix repo URLs for badges [\#38](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/38) ([felixbuenemann](https://github.com/felixbuenemann)) +- Clarify README about unique expiration [\#36](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/36) ([spacemunkay](https://github.com/spacemunkay)) +- Add option to make jobs unique on all queues [\#32](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/32) ([robinmessage](https://github.com/robinmessage)) +- Fix homepage in gemspec [\#29](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/29) ([tmaier](https://github.com/tmaier)) + +## [v2.7.0](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v2.7.0) (2013-11-24) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v2.3.2...v2.7.0) + +**Closed issues:** + +- Sidekiq tests failed when sidekiq-unique-jobs is used [\#24](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/24) +- Redis not mocked in testing [\#18](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/18) +- Scheduled Unique Jobs Not Being Enqueued [\#15](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/15) +- Retries duplicates unique jobs [\#5](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/5) +- Middleware not added to chain? [\#2](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/2) + +**Merged pull requests:** + +- Make unlock/yield order configurable. [\#21](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/21) ([endofunky](https://github.com/endofunky)) +- Rely on Sidekiq's String\#constantize extension instead of rolling our own [\#19](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/19) ([disbelief](https://github.com/disbelief)) +- Attempt to constantize String `worker\_class` arguments passed to client middleware [\#17](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/17) ([disbelief](https://github.com/disbelief)) +- Compatibility with Sidekiq 2.12.1 Scheduled Jobs [\#16](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/16) ([lsimoneau](https://github.com/lsimoneau)) +- Allow worker to specify which arguments to include in uniquing hash [\#12](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/12) ([sax](https://github.com/sax)) +- Add support for unique when using Sidekiq's delay function [\#11](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/11) ([eduardosasso](https://github.com/eduardosasso)) +- Adding the unique prefix option [\#8](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/8) ([KensoDev](https://github.com/KensoDev)) +- Remove unnecessary log messages [\#7](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/7) ([marclennox](https://github.com/marclennox)) + +## [v2.3.2](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v2.3.2) (2012-09-27) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v2.2.1...v2.3.2) + +**Closed issues:** + +- Scheduled workers [\#1](https://github.com/mhenrixon/sidekiq-unique-jobs/issues/1) + +**Merged pull requests:** + +- Fix multiple bugs, cleaned up dependencies, and added a feature [\#4](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/4) ([kemper-blinq](https://github.com/kemper-blinq)) +- Dependency on sidekiq 2.2.0 and up [\#3](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/3) ([philostler](https://github.com/philostler)) + +## [v2.2.1](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v2.2.1) (2012-08-19) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v2.2.0...v2.2.1) + +## [v2.2.0](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v2.2.0) (2012-08-19) +[Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v2.1.0...v2.2.0) + +## [v2.1.0](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v2.1.0) (2012-08-07) + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file diff --git a/Gemfile b/Gemfile index 51306d8ab..539fdff9e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,24 +1,32 @@ # frozen_string_literal: true -source 'https://rubygems.org' +source "https://rubygems.org" gemspec -gem 'appraisal', '~> 2.2.0' -gem 'rspec-its', require: false -gem 'rspec-retry', require: false -gem 'rspec-eventually', require: false +gem "appraisal", "~> 2.2.0" +gem "rspec-eventually", require: false +gem "rspec-its", require: false +gem "rspec-retry", require: false platforms :mri_25 do - gem 'benchmark-ips', require: false - gem 'fasterer', require: false - gem 'guard', require: false - gem 'guard-reek', require: false - gem 'guard-rspec', require: false - gem 'guard-rubocop', require: false - gem 'memory_profiler', require: false - gem 'pry-byebug', require: false - gem 'rubocop', require: false - gem 'rubocop-rspec', require: false - gem 'simplecov-json', require: false - gem 'travis', require: false + gem "benchmark-ips" + gem "fasterer" + gem "fuubar" + gem "gem-release" + gem "github-markup" + gem "github_changelog_generator" + gem "guard" + gem "guard-reek" + gem "guard-rspec" + gem "guard-rubocop" + gem "memory_profiler" + gem "pry" + gem "rb-readline" + gem "redcarpet" + gem "reek", ">= 5.3" + gem "rubocop" + gem "rubocop-rspec" + gem "simplecov-json" + gem "travis" + gem "yard" end diff --git a/Guardfile b/Guardfile index b9b18024b..4dae91cad 100644 --- a/Guardfile +++ b/Guardfile @@ -1,35 +1,7 @@ -# A sample Guardfile -# More info at https://github.com/guard/guard#readme - -## Uncomment and set this to only include directories you want to watch -# directories %w(app lib config test spec features) \ -# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")} - -## Note: if you are using the `directories` clause above and you are not -## watching the project directory ('.'), then you will want to move -## the Guardfile to a watched dir and symlink it back, e.g. -# -# $ mkdir config -# $ mv Guardfile config/ -# $ ln -s config/Guardfile . -# -# and, you'll have to watch "config/Guardfile" instead of "Guardfile" - -# Note: The cmd option is now required due to the increasing number of ways -# rspec may be run, below are examples of the most common uses. -# * bundler: 'bundle exec rspec' -# * bundler binstubs: 'bin/rspec' -# * spring: 'bin/rspec' (This will use spring if running and you have -# installed the spring binstubs per the docs) -# * zeus: 'zeus rspec' (requires the server to be started separately) -# * 'just' rspec: 'rspec' - guard :rspec, cmd: "env COV=false bundle exec rspec" do require "guard/rspec/dsl" dsl = Guard::RSpec::Dsl.new(self) - # Feel free to open issues for suggestions and improvements - # RSpec files rspec = dsl.rspec watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" } @@ -39,7 +11,6 @@ guard :rspec, cmd: "env COV=false bundle exec rspec" do watch(rspec.spec_support) { rspec.spec_dir } watch(rspec.spec_files) - # Ruby files ruby = dsl.ruby dsl.watch_spec_files_for(ruby.lib_files) end diff --git a/README.md b/README.md index 1e6a50722..a86c627e6 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,45 @@ # SidekiqUniqueJobs [![Join the chat at https://gitter.im/mhenrixon/sidekiq-unique-jobs](https://badges.gitter.im/mhenrixon/sidekiq-unique-jobs.svg)](https://gitter.im/mhenrixon/sidekiq-unique-jobs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/mhenrixon/sidekiq-unique-jobs.png?branch=master)](https://travis-ci.org/mhenrixon/sidekiq-unique-jobs) [![Code Climate](https://codeclimate.com/github/mhenrixon/sidekiq-unique-jobs.png)](https://codeclimate.com/github/mhenrixon/sidekiq-unique-jobs) [![Test Coverage](https://codeclimate.com/github/mhenrixon/sidekiq-unique-jobs/badges/coverage.svg)](https://codeclimate.com/github/mhenrixon/sidekiq-unique-jobs/coverage) -## Table of contents - -* [Introduction](#introduction) -* [Documentation](#documentation) -* [Requirements](#requirements) -* [Installation](#installation) -* [Support Me](#support-me) -* [General Information](#general-information) -* [Options](#options) - * [Lock Expiration](#lock-expiration) - * [Lock Timeout](#lock-timeout) - * [Unique Across Queues](#unique-across-queues) - * [Unique Across Workers](#unique-across-workers) -* [Locks](#locks) - * [Until Executing](#until-executing) - * [Until Executed](#until-executed) - * [Until Timeout](#until-timeout) - * [Unique Until And While Executing](#unique-until-and-while-executing) - * [While Executing](#while-executing) -* [Conflict Strategy](#conflict-strategy) - * [Log](#log) - * [Raise](#raise) - * [Reject](#reject) - * [Replace](#replace) - * [Reschedule](#reschedule) -* [Usage](#usage) - * [Finer Control over Uniqueness](#finer-control-over-uniqueness) - * [After Unlock Callback](#after-unlock-callback) - * [Logging](#logging) - * [Cleanup Dead Locks](#cleanup-dead-locks) -* [Debugging](#debugging) - * [Sidekiq Web](#sidekiq-web) - * [Show Unique Digests](#show-unique-digests) - * [Show keys for digest](#show-keys-for-digest) -* [Communication](#communication) -* [Testing](#testing) -* [Contributing](#contributing) -* [Contributors](#contributors) + + +- [Introduction](#introduction) +- [Documentation](#documentation) +- [Requirements](#requirements) +- [Installation](#installation) +- [Support Me](#support-me) +- [General Information](#general-information) +- [Options](#options) + - [Lock Expiration](#lock-expiration) + - [Lock Timeout](#lock-timeout) + - [Unique Across Queues](#unique-across-queues) + - [Unique Across Workers](#unique-across-workers) +- [Locks](#locks) + - [Until Executing](#until-executing) + - [Until Executed](#until-executed) + - [Until Timeout](#until-timeout) + - [Unique Until And While Executing](#unique-until-and-while-executing) + - [While Executing](#while-executing) +- [Conflict Strategy](#conflict-strategy) + - [Log](#log) + - [Raise](#raise) + - [Reject](#reject) + - [Replace](#replace) + - [Reschedule](#reschedule) +- [Usage](#usage) + - [Finer Control over Uniqueness](#finer-control-over-uniqueness) + - [After Unlock Callback](#after-unlock-callback) + - [Logging](#logging) + - [Cleanup Dead Locks](#cleanup-dead-locks) +- [Debugging](#debugging) + - [Sidekiq Web](#sidekiq-web) + - [Show Unique Digests](#show-unique-digests) + - [Show keys for digest](#show-keys-for-digest) +- [Communication](#communication) +- [Testing](#testing) +- [Contributing](#contributing) +- [Contributors](#contributors) + + ## Introduction @@ -45,16 +47,16 @@ The goal of this gem is to ensure your Sidekiq jobs are unique. We do this by cr ## Documentation -This is the documentation for the master branch. You can find the documentation for each release by navigating to its tag: https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.10. +This is the documentation for the master branch. You can find the documentation for each release by navigating to its tag: [v5.0.10][] Below are links to the latest major versions (4 & 5): -- [v5.0.10](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.10) -- [v4.0.18](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.18) +- [v5.0.10][] +- [v4.0.18][] ## Requirements -See https://github.com/mperham/sidekiq#requirements for what is required. Starting from 5.0.0 only sidekiq >= 4 is supported and support for MRI <= 2.1 is dropped. ActiveJob is not supported +See [Sidekiq requirements][] for what is required. Starting from 5.0.0 only sidekiq >= 4 is supported and support for MRI <= 2.1 is dropped. ActiveJob is not supported Version 6 requires Redis >= 3 and pure Sidekiq, no ActiveJob supported anymore. See [About ActiveJob](https://github.com/mhenrixon/sidekiq-unique-jobs/wiki/About-ActiveJob) for why. @@ -62,20 +64,25 @@ Version 6 requires Redis >= 3 and pure Sidekiq, no ActiveJob supported anymore. Add this line to your application's Gemfile: - gem 'sidekiq-unique-jobs' +``` +gem 'sidekiq-unique-jobs' +``` And then execute: - $ bundle +``` +bundle +``` Or install it yourself as: - $ gem install sidekiq-unique-jobs - +``` +gem install sidekiq-unique-jobs +``` ## Support Me -Want to show me some ❤️ for the hard work I do on this gem? You can use the following PayPal link https://paypal.me/mhenrixon. Any amount is welcome and let me tell you it feels good to be appreciated. Even a dollar makes me super excited about all of this. +Want to show me some ❤️ for the hard work I do on this gem? You can use the following [PayPal link][]. Any amount is welcome and let me tell you it feels good to be appreciated. Even a dollar makes me super excited about all of this. ## General Information @@ -115,7 +122,7 @@ This configuration option is slightly misleading. It doesn't disregard the queue ```ruby class Worker include Sidekiq::Worker - + sidekiq_options unique_across_queues: true, queue: 'default' def perform(args); end @@ -131,7 +138,7 @@ This configuration option is slightly misleading. It doesn't disregard the worke ```ruby class WorkerOne include Sidekiq::Worker - + sidekiq_options unique_across_workers: true, queue: 'default' def perform(args); end @@ -139,17 +146,17 @@ end class WorkerTwo include Sidekiq::Worker - + sidekiq_options unique_across_workers: true, queue: 'default' def perform(args); end end -WorkerOne.perform_async(1) +WorkerOne.perform_async(1) # => 'the jobs unique id' -WorkerTwo.perform_async(1) +WorkerTwo.perform_async(1) # => nil because WorkerOne just stole the lock ``` @@ -220,7 +227,7 @@ In the console you should see something like: ## Conflict Strategy -Decides how we handle conflict. We can either reject the job to the dead queue or reschedule it. Both are useful for jobs that absolutely need to run and have been configured to use the lock `WhileExecuting` that is used only by the sidekiq server process. +Decides how we handle conflict. We can either reject the job to the dead queue or reschedule it. Both are useful for jobs that absolutely need to run and have been configured to use the lock `WhileExecuting` that is used only by the sidekiq server process. The last one is log which can be be used with the lock `UntilExecuted` and `UntilExpired`. Now we write a log entry saying the job could not be pushed because it is a duplicate of another job with the same arguments @@ -246,9 +253,9 @@ This strategy is intended to be used with `WhileExecuting` and will push the job This strategy is intended to be used with client locks like `UntilExecuted`. It will delete any existing job for these arguments from retry, schedule and -queue and retry the lock again. +queue and retry the lock again. -This is slightly dangerous and should probably only be used for jobs that are +This is slightly dangerous and should probably only be used for jobs that are always scheduled in the future. Currently only attempting to retry one time. `sidekiq_options lock: :until_executed, on_conflict: :replace` @@ -322,7 +329,7 @@ end ### After Unlock Callback -If you need to perform any additional work after the lock has been released you can provide an `#after_unlock` instance method. The method will be called when the lock has been unlocked. Most times this means after yield but there are two exceptions to that. +If you need to perform any additional work after the lock has been released you can provide an `#after_unlock` instance method. The method will be called when the lock has been unlocked. Most times this means after yield but there are two exceptions to that. **Exception 1:** UntilExecuting unlocks and calls back before yielding. **Exception 2:** UntilExpired expires eventually, no after_unlock hook is called. @@ -391,12 +398,11 @@ require 'sidekiq_unique_jobs/web' mount Sidekiq::Web, at: '/sidekiq' ``` -There is no need to `require 'sidekiq/web'` since `sidekiq_unique_jobs/web` +There is no need to `require 'sidekiq/web'` since `sidekiq_unique_jobs/web` already does this. To filter/search for keys we can use the wildcard `*`. If we have a unique digest `'uniquejobs:9e9b5ce5d423d3ea470977004b50ff84` we can search for it by enter `*ff84` and it should return all digests that end with `ff84`. - #### Show Unique Digests ![Unique Digests](assets/unique_digests_1.png) @@ -413,7 +419,7 @@ There is a [![Join the chat at https://gitter.im/mhenrixon/sidekiq-unique-jobs]( This has been probably the most confusing part of this gem. People get really confused with how unreliable the unique jobs have been. I there for decided to do what Mike is doing for sidekiq enterprise. Read the section about unique jobs. -https://www.dailydrip.com/topics/sidekiq/drips/sidekiq-enterprise-unique-jobs +[Enterprise unique jobs][] ```ruby SidekiqUniqueJobs.configure do |config| @@ -462,12 +468,18 @@ I would strongly suggest you let this gem test uniqueness. If you care about how ## Contributing 1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request +1. Create your feature branch (`git checkout -b my-new-feature`) +1. Commit your changes (`git commit -am 'Add some feature'`) +1. Push to the branch (`git push origin my-new-feature`) +1. Create new Pull Request +## Contributors -## Contributors +You can find a list of contributors over on [Contributors][] -You can find a list of contributors over on https://github.com/mhenrixon/sidekiq-unique-jobs/graphs/contributors +[v5.0.10]: https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v5.0.10. +[v4.0.18]: https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v4.0.18 +[Sidekiq requirements]: https://github.com/mperham/sidekiq#requirements +[Enterprise unique jobs]: https://www.dailydrip.com/topics/sidekiq/drips/sidekiq-enterprise-unique-jobs +[Contributors]: https://github.com/mhenrixon/sidekiq-unique-jobs/graphs/contributors +[Paypal link https://paypal.me/mhenrixon]: https://paypal.me/mhenrixon diff --git a/Rakefile b/Rakefile index 964485ca6..0d4953197 100644 --- a/Rakefile +++ b/Rakefile @@ -1,12 +1,29 @@ # frozen_string_literal: true -require 'rubygems' -require 'bundler/setup' -require 'bundler/gem_tasks' -require 'rspec/core/rake_task' -require 'rubocop/rake_task' +require "rspec/core/rake_task" +require "rubocop/rake_task" + +Dir.glob("#{File.expand_path(__dir__)}/lib/tasks/**/*.rake").each { |f| import f } RuboCop::RakeTask.new(:style) RSpec::Core::RakeTask.new(:spec) +require "yard" +YARD::Rake::YardocTask.new do |t| + t.files = %w[lib/sidekiq_unique_jobs/**/*.rb"] + t.options = %w[ + --no-private + --markup=markdown + --markup-provider=redcarpet + --readme README.md + ] +end + task default: [:style, :spec] + +task :release do + sh("./update_docs.sh") + sh("gem release --tag --push") + Rake::Task["changelog"].invoke + sh("gem bump") +end diff --git a/bin/bench b/bin/bench index ea9aa44b9..d1086cc4e 100755 --- a/bin/bench +++ b/bin/bench @@ -3,17 +3,17 @@ # Trap interrupts to quit cleanly. See # https://twitter.com/mitchellh/status/283014103189053442 -Signal.trap('INT') { abort } +Signal.trap("INT") { abort } -require 'bundler/setup' -require 'benchmark/ips' -require 'sidekiq-unique-jobs' +require "bundler/setup" +require "benchmark/ips" +require "sidekiq-unique-jobs" ITERATIONS ||= 10_000 Benchmark.ips do |x| x.config(time: 5, warmup: 2) - x.report('new_shit') do |_times| + x.report("new_shit") do |_times| SidekiqUniqueJobs::Scripts::AcquireLock.execute(nil, SecureRandom.hex, SecureRandom.hex) end x.compare! diff --git a/bin/uniquejobs b/bin/uniquejobs index 1ac931250..923d479b8 100755 --- a/bin/uniquejobs +++ b/bin/uniquejobs @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require 'bundler/setup' -require 'sidekiq_unique_jobs' +require "bundler/setup" +require "sidekiq_unique_jobs" SidekiqUniqueJobs::Cli.start(ARGV) diff --git a/examples/custom_queue_job.rb b/examples/custom_queue_job.rb index 83bb07329..523769ae3 100644 --- a/examples/custom_queue_job.rb +++ b/examples/custom_queue_job.rb @@ -6,7 +6,7 @@ class CustomQueueJob include Sidekiq::Worker sidekiq_options queue: :customqueue - def perform(one, two = 'two') + def perform(one, two = "two") [one, two] end end diff --git a/examples/custom_queue_job_with_filter_method.rb b/examples/custom_queue_job_with_filter_method.rb index d7b9d0e13..ac8be5891 100644 --- a/examples/custom_queue_job_with_filter_method.rb +++ b/examples/custom_queue_job_with_filter_method.rb @@ -2,7 +2,7 @@ # :nocov: -require_relative 'custom_queue_job' +require_relative "custom_queue_job" class CustomQueueJobWithFilterMethod < CustomQueueJob sidekiq_options lock: :until_executed, unique_args: :args_filter diff --git a/examples/custom_queue_job_with_filter_proc.rb b/examples/custom_queue_job_with_filter_proc.rb index 01d13b761..34f6d3a02 100644 --- a/examples/custom_queue_job_with_filter_proc.rb +++ b/examples/custom_queue_job_with_filter_proc.rb @@ -2,7 +2,7 @@ # :nocov: -require_relative './custom_queue_job' +require_relative "./custom_queue_job" class CustomQueueJobWithFilterProc < CustomQueueJob # slightly contrived example of munging args to the @@ -10,7 +10,7 @@ class CustomQueueJobWithFilterProc < CustomQueueJob sidekiq_options lock: :until_expired, unique_args: (lambda do |args| options = args.extract_options! - options.delete('random') + options.delete("random") args + [options] end) end diff --git a/examples/my_unique_job_with_filter_method.rb b/examples/my_unique_job_with_filter_method.rb index 1822475d5..42a924f69 100644 --- a/examples/my_unique_job_with_filter_method.rb +++ b/examples/my_unique_job_with_filter_method.rb @@ -16,6 +16,6 @@ def perform(*) def self.filtered_args(args) options = args.extract_options! - [args.first, options['type']] + [args.first, options["type"]] end end diff --git a/examples/my_unique_job_with_filter_proc.rb b/examples/my_unique_job_with_filter_proc.rb index a424330ac..b1c653faa 100644 --- a/examples/my_unique_job_with_filter_proc.rb +++ b/examples/my_unique_job_with_filter_proc.rb @@ -10,7 +10,7 @@ class MyUniqueJobWithFilterProc retry: true, unique_args: (lambda do |args| options = args.extract_options! - [args.first, options['type']] + [args.first, options["type"]] end) def perform(*) diff --git a/examples/unique_job_with_filter_method.rb b/examples/unique_job_with_filter_method.rb index af2e8a16e..a94345d01 100644 --- a/examples/unique_job_with_filter_method.rb +++ b/examples/unique_job_with_filter_method.rb @@ -16,6 +16,6 @@ def perform(*) def self.filtered_args(args) options = args.extract_options! - [args.first, options['type']] + [args.first, options["type"]] end end diff --git a/gemfiles/sidekiq_4.0.gemfile b/gemfiles/sidekiq_4.0.gemfile index 37fa2e8f2..8b46dc076 100644 --- a/gemfiles/sidekiq_4.0.gemfile +++ b/gemfiles/sidekiq_4.0.gemfile @@ -3,24 +3,32 @@ source "https://rubygems.org" gem "appraisal", "~> 2.2.0" +gem "rspec-eventually", require: false gem "rspec-its", require: false gem "rspec-retry", require: false -gem "rspec-eventually", require: false gem "sidekiq", "~> 4.0.0" platforms :mri_25 do - gem "benchmark-ips", require: false - gem "fasterer", require: false - gem "guard", require: false - gem "guard-reek", require: false - gem "guard-rspec", require: false - gem "guard-rubocop", require: false - gem "memory_profiler", require: false - gem "pry-byebug", require: false - gem "rubocop", require: false - gem "rubocop-rspec", require: false - gem "simplecov-json", require: false - gem "travis", require: false + gem "benchmark-ips" + gem "fasterer" + gem "fuubar" + gem "gem-release" + gem "github-markup" + gem "github_changelog_generator" + gem "guard" + gem "guard-reek" + gem "guard-rspec" + gem "guard-rubocop" + gem "memory_profiler" + gem "pry" + gem "rb-readline" + gem "redcarpet" + gem "reek", ">= 5.3" + gem "rubocop" + gem "rubocop-rspec" + gem "simplecov-json" + gem "travis" + gem "yard" end gemspec path: "../" diff --git a/gemfiles/sidekiq_4.1.gemfile b/gemfiles/sidekiq_4.1.gemfile index 879617936..c92fb5e34 100644 --- a/gemfiles/sidekiq_4.1.gemfile +++ b/gemfiles/sidekiq_4.1.gemfile @@ -3,24 +3,32 @@ source "https://rubygems.org" gem "appraisal", "~> 2.2.0" +gem "rspec-eventually", require: false gem "rspec-its", require: false gem "rspec-retry", require: false -gem "rspec-eventually", require: false gem "sidekiq", "~> 4.1.0" platforms :mri_25 do - gem "benchmark-ips", require: false - gem "fasterer", require: false - gem "guard", require: false - gem "guard-reek", require: false - gem "guard-rspec", require: false - gem "guard-rubocop", require: false - gem "memory_profiler", require: false - gem "pry-byebug", require: false - gem "rubocop", require: false - gem "rubocop-rspec", require: false - gem "simplecov-json", require: false - gem "travis", require: false + gem "benchmark-ips" + gem "fasterer" + gem "fuubar" + gem "gem-release" + gem "github-markup" + gem "github_changelog_generator" + gem "guard" + gem "guard-reek" + gem "guard-rspec" + gem "guard-rubocop" + gem "memory_profiler" + gem "pry" + gem "rb-readline" + gem "redcarpet" + gem "reek", ">= 5.3" + gem "rubocop" + gem "rubocop-rspec" + gem "simplecov-json" + gem "travis" + gem "yard" end gemspec path: "../" diff --git a/gemfiles/sidekiq_4.2.gemfile b/gemfiles/sidekiq_4.2.gemfile index d7e9bca71..1ec655215 100644 --- a/gemfiles/sidekiq_4.2.gemfile +++ b/gemfiles/sidekiq_4.2.gemfile @@ -3,24 +3,32 @@ source "https://rubygems.org" gem "appraisal", "~> 2.2.0" +gem "rspec-eventually", require: false gem "rspec-its", require: false gem "rspec-retry", require: false -gem "rspec-eventually", require: false gem "sidekiq", "~> 4.2.0" platforms :mri_25 do - gem "benchmark-ips", require: false - gem "fasterer", require: false - gem "guard", require: false - gem "guard-reek", require: false - gem "guard-rspec", require: false - gem "guard-rubocop", require: false - gem "memory_profiler", require: false - gem "pry-byebug", require: false - gem "rubocop", require: false - gem "rubocop-rspec", require: false - gem "simplecov-json", require: false - gem "travis", require: false + gem "benchmark-ips" + gem "fasterer" + gem "fuubar" + gem "gem-release" + gem "github-markup" + gem "github_changelog_generator" + gem "guard" + gem "guard-reek" + gem "guard-rspec" + gem "guard-rubocop" + gem "memory_profiler" + gem "pry" + gem "rb-readline" + gem "redcarpet" + gem "reek", ">= 5.3" + gem "rubocop" + gem "rubocop-rspec" + gem "simplecov-json" + gem "travis" + gem "yard" end gemspec path: "../" diff --git a/gemfiles/sidekiq_5.0.gemfile b/gemfiles/sidekiq_5.0.gemfile index a16fe99e2..2b16b9fd4 100644 --- a/gemfiles/sidekiq_5.0.gemfile +++ b/gemfiles/sidekiq_5.0.gemfile @@ -3,24 +3,32 @@ source "https://rubygems.org" gem "appraisal", "~> 2.2.0" +gem "rspec-eventually", require: false gem "rspec-its", require: false gem "rspec-retry", require: false -gem "rspec-eventually", require: false gem "sidekiq", "~> 5.0.0" platforms :mri_25 do - gem "benchmark-ips", require: false - gem "fasterer", require: false - gem "guard", require: false - gem "guard-reek", require: false - gem "guard-rspec", require: false - gem "guard-rubocop", require: false - gem "memory_profiler", require: false - gem "pry-byebug", require: false - gem "rubocop", require: false - gem "rubocop-rspec", require: false - gem "simplecov-json", require: false - gem "travis", require: false + gem "benchmark-ips" + gem "fasterer" + gem "fuubar" + gem "gem-release" + gem "github-markup" + gem "github_changelog_generator" + gem "guard" + gem "guard-reek" + gem "guard-rspec" + gem "guard-rubocop" + gem "memory_profiler" + gem "pry" + gem "rb-readline" + gem "redcarpet" + gem "reek", ">= 5.3" + gem "rubocop" + gem "rubocop-rspec" + gem "simplecov-json" + gem "travis" + gem "yard" end gemspec path: "../" diff --git a/gemfiles/sidekiq_5.1.gemfile b/gemfiles/sidekiq_5.1.gemfile index 4124fd0ad..b028f3276 100644 --- a/gemfiles/sidekiq_5.1.gemfile +++ b/gemfiles/sidekiq_5.1.gemfile @@ -3,24 +3,32 @@ source "https://rubygems.org" gem "appraisal", "~> 2.2.0" +gem "rspec-eventually", require: false gem "rspec-its", require: false gem "rspec-retry", require: false -gem "rspec-eventually", require: false gem "sidekiq", "~> 5.1.0" platforms :mri_25 do - gem "benchmark-ips", require: false - gem "fasterer", require: false - gem "guard", require: false - gem "guard-reek", require: false - gem "guard-rspec", require: false - gem "guard-rubocop", require: false - gem "memory_profiler", require: false - gem "pry-byebug", require: false - gem "rubocop", require: false - gem "rubocop-rspec", require: false - gem "simplecov-json", require: false - gem "travis", require: false + gem "benchmark-ips" + gem "fasterer" + gem "fuubar" + gem "gem-release" + gem "github-markup" + gem "github_changelog_generator" + gem "guard" + gem "guard-reek" + gem "guard-rspec" + gem "guard-rubocop" + gem "memory_profiler" + gem "pry" + gem "rb-readline" + gem "redcarpet" + gem "reek", ">= 5.3" + gem "rubocop" + gem "rubocop-rspec" + gem "simplecov-json" + gem "travis" + gem "yard" end gemspec path: "../" diff --git a/gemfiles/sidekiq_5.2.gemfile b/gemfiles/sidekiq_5.2.gemfile index 8486d5887..a0b981cb2 100644 --- a/gemfiles/sidekiq_5.2.gemfile +++ b/gemfiles/sidekiq_5.2.gemfile @@ -3,24 +3,32 @@ source "https://rubygems.org" gem "appraisal", "~> 2.2.0" +gem "rspec-eventually", require: false gem "rspec-its", require: false gem "rspec-retry", require: false -gem "rspec-eventually", require: false gem "sidekiq", "~> 5.2.0" platforms :mri_25 do - gem "benchmark-ips", require: false - gem "fasterer", require: false - gem "guard", require: false - gem "guard-reek", require: false - gem "guard-rspec", require: false - gem "guard-rubocop", require: false - gem "memory_profiler", require: false - gem "pry-byebug", require: false - gem "rubocop", require: false - gem "rubocop-rspec", require: false - gem "simplecov-json", require: false - gem "travis", require: false + gem "benchmark-ips" + gem "fasterer" + gem "fuubar" + gem "gem-release" + gem "github-markup" + gem "github_changelog_generator" + gem "guard" + gem "guard-reek" + gem "guard-rspec" + gem "guard-rubocop" + gem "memory_profiler" + gem "pry" + gem "rb-readline" + gem "redcarpet" + gem "reek", ">= 5.3" + gem "rubocop" + gem "rubocop-rspec" + gem "simplecov-json" + gem "travis" + gem "yard" end gemspec path: "../" diff --git a/gemfiles/sidekiq_develop.gemfile b/gemfiles/sidekiq_develop.gemfile index b32106194..a3da1b982 100644 --- a/gemfiles/sidekiq_develop.gemfile +++ b/gemfiles/sidekiq_develop.gemfile @@ -3,24 +3,32 @@ source "https://rubygems.org" gem "appraisal", "~> 2.2.0" +gem "rspec-eventually", require: false gem "rspec-its", require: false gem "rspec-retry", require: false -gem "rspec-eventually", require: false gem "sidekiq", git: "https://github.com/mperham/sidekiq.git" platforms :mri_25 do - gem "benchmark-ips", require: false - gem "fasterer", require: false - gem "guard", require: false - gem "guard-reek", require: false - gem "guard-rspec", require: false - gem "guard-rubocop", require: false - gem "memory_profiler", require: false - gem "pry-byebug", require: false - gem "rubocop", require: false - gem "rubocop-rspec", require: false - gem "simplecov-json", require: false - gem "travis", require: false + gem "benchmark-ips" + gem "fasterer" + gem "fuubar" + gem "gem-release" + gem "github-markup" + gem "github_changelog_generator" + gem "guard" + gem "guard-reek" + gem "guard-rspec" + gem "guard-rubocop" + gem "memory_profiler" + gem "pry" + gem "rb-readline" + gem "redcarpet" + gem "reek", ">= 5.3" + gem "rubocop" + gem "rubocop-rspec" + gem "simplecov-json" + gem "travis" + gem "yard" end gemspec path: "../" diff --git a/lib/sidekiq-unique-jobs.rb b/lib/sidekiq-unique-jobs.rb index 65e6507b3..2ac110655 100644 --- a/lib/sidekiq-unique-jobs.rb +++ b/lib/sidekiq-unique-jobs.rb @@ -1,3 +1,3 @@ # frozen_string_literal: true -require 'sidekiq_unique_jobs' +require "sidekiq_unique_jobs" diff --git a/lib/sidekiq_unique_jobs.rb b/lib/sidekiq_unique_jobs.rb index 36cff1db2..966fb6682 100644 --- a/lib/sidekiq_unique_jobs.rb +++ b/lib/sidekiq_unique_jobs.rb @@ -1,109 +1,36 @@ # frozen_string_literal: true -require 'yaml' if RUBY_VERSION.include?('2.0.0') -require 'forwardable' -require 'concurrent/mutable_struct' -require 'ostruct' - -require 'sidekiq_unique_jobs/version' -require 'sidekiq_unique_jobs/constants' -require 'sidekiq_unique_jobs/logging' -require 'sidekiq_unique_jobs/sidekiq_worker_methods' -require 'sidekiq_unique_jobs/connection' -require 'sidekiq_unique_jobs/exceptions' -require 'sidekiq_unique_jobs/job' -require 'sidekiq_unique_jobs/util' -require 'sidekiq_unique_jobs/digests' -require 'sidekiq_unique_jobs/cli' -require 'sidekiq_unique_jobs/core_ext' -require 'sidekiq_unique_jobs/timeout' -require 'sidekiq_unique_jobs/scripts' -require 'sidekiq_unique_jobs/unique_args' -require 'sidekiq_unique_jobs/unlockable' -require 'sidekiq_unique_jobs/locksmith' -require 'sidekiq_unique_jobs/lock/base_lock' -require 'sidekiq_unique_jobs/lock/until_executed' -require 'sidekiq_unique_jobs/lock/until_executing' -require 'sidekiq_unique_jobs/lock/until_expired' -require 'sidekiq_unique_jobs/lock/while_executing' -require 'sidekiq_unique_jobs/lock/while_executing_reject' -require 'sidekiq_unique_jobs/lock/until_and_while_executing' -require 'sidekiq_unique_jobs/options_with_fallback' -require 'sidekiq_unique_jobs/middleware' -require 'sidekiq_unique_jobs/sidekiq_unique_ext' -require 'sidekiq_unique_jobs/on_conflict' - -# Namespace for this gem -# -# Contains configuration and utility methods that belongs top level -# -# @author Mikael Henriksson -module SidekiqUniqueJobs - include SidekiqUniqueJobs::Connection - - module_function - - Config = Concurrent::MutableStruct.new( - :default_lock_timeout, - :enabled, - :unique_prefix, - :logger, - ) - - # The current configuration (See: {.configure} on how to configure) - def config - # Arguments here need to match the definition of the new class (see above) - @config ||= Config.new( - 0, - true, - 'uniquejobs', - Sidekiq.logger, - ) - end - - # The current logger - # @return [Logger] the configured logger - def logger - config.logger - end - - # Set a new logger - # @param [Logger] other a new logger - def logger=(other) - config.logger = other - end - - # Change global configuration while yielding - # @yield control to the caller - def use_config(tmp_config) - fail ::ArgumentError, "#{name}.#{__method__} needs a block" unless block_given? - - old_config = config.to_h - configure(tmp_config) - yield - configure(old_config) - end - - # Configure the gem - # - # This is usually called once at startup of an application - # @param [Hash] options global gem options - # @option options [Integer] :default_lock_timeout (default is 0) - # @option options [true,false] :enabled (default is true) - # @option options [String] :unique_prefix (default is 'uniquejobs') - # @option options [Logger] :logger (default is Sidekiq.logger) - # @yield control to the caller when given block - def configure(options = {}) - if block_given? - yield config - else - options.each do |key, val| - config.send("#{key}=", val) - end - end - end - - def redis_version - @redis_version ||= redis { |conn| conn.info('server')['redis_version'] } - end -end +require "yaml" if RUBY_VERSION.include?("2.0.0") +require "forwardable" +require "concurrent/mutable_struct" +require "ostruct" + +require "sidekiq_unique_jobs/version" +require "sidekiq_unique_jobs/constants" +require "sidekiq_unique_jobs/logging" +require "sidekiq_unique_jobs/sidekiq_worker_methods" +require "sidekiq_unique_jobs/connection" +require "sidekiq_unique_jobs/exceptions" +require "sidekiq_unique_jobs/job" +require "sidekiq_unique_jobs/util" +require "sidekiq_unique_jobs/digests" +require "sidekiq_unique_jobs/cli" +require "sidekiq_unique_jobs/core_ext" +require "sidekiq_unique_jobs/timeout" +require "sidekiq_unique_jobs/scripts" +require "sidekiq_unique_jobs/unique_args" +require "sidekiq_unique_jobs/unlockable" +require "sidekiq_unique_jobs/locksmith" +require "sidekiq_unique_jobs/lock/base_lock" +require "sidekiq_unique_jobs/lock/until_executed" +require "sidekiq_unique_jobs/lock/until_executing" +require "sidekiq_unique_jobs/lock/until_expired" +require "sidekiq_unique_jobs/lock/while_executing" +require "sidekiq_unique_jobs/lock/while_executing_reject" +require "sidekiq_unique_jobs/lock/until_and_while_executing" +require "sidekiq_unique_jobs/options_with_fallback" +require "sidekiq_unique_jobs/middleware" +require "sidekiq_unique_jobs/sidekiq_unique_ext" +require "sidekiq_unique_jobs/on_conflict" + +require "sidekiq_unique_jobs/sidekiq_unique_jobs" diff --git a/lib/sidekiq_unique_jobs/cli.rb b/lib/sidekiq_unique_jobs/cli.rb index f7a066aa2..8dc12fba3 100644 --- a/lib/sidekiq_unique_jobs/cli.rb +++ b/lib/sidekiq_unique_jobs/cli.rb @@ -1,24 +1,29 @@ # frozen_string_literal: true -require 'thor' +require "thor" module SidekiqUniqueJobs + # + # Command line interface for unique jobs + # + # @author Mikael Henriksson + # class Cli < Thor def self.banner(command, _namespace = nil, _subcommand = false) "jobs #{@package_name} #{command.usage}" end - desc 'keys PATTERN', 'list all unique keys and their expiry time' - option :count, aliases: :c, type: :numeric, default: 1000, desc: 'The max number of keys to return' - def keys(pattern = '*') + desc "keys PATTERN", "list all unique keys and their expiry time" + option :count, aliases: :c, type: :numeric, default: 1000, desc: "The max number of keys to return" + def keys(pattern = "*") keys = Util.keys(pattern, options[:count]) say "Found #{keys.size} keys matching '#{pattern}':" print_in_columns(keys.sort) if keys.any? end - desc 'del PATTERN', 'deletes unique keys from redis by pattern' - option :dry_run, aliases: :d, type: :boolean, desc: 'set to false to perform deletion' - option :count, aliases: :c, type: :numeric, default: 1000, desc: 'The max number of keys to return' + desc "del PATTERN", "deletes unique keys from redis by pattern" + option :dry_run, aliases: :d, type: :boolean, desc: "set to false to perform deletion" + option :count, aliases: :c, type: :numeric, default: 1000, desc: "The max number of keys to return" def del(pattern) max_count = options[:count] if options[:dry_run] @@ -30,7 +35,7 @@ def del(pattern) end end - desc 'console', 'drop into a console with easy access to helper methods' + desc "console", "drop into a console with easy access to helper methods" def console say "Use `keys '*', 1000 to display the first 1000 unique keys matching '*'" say "Use `del '*', 1000, true (default) to see how many keys would be deleted for the pattern '*'" @@ -41,10 +46,10 @@ def console no_commands do def console_class - require 'pry' + require "pry" Pry rescue LoadError - require 'irb' + require "irb" IRB end end diff --git a/lib/sidekiq_unique_jobs/client/middleware.rb b/lib/sidekiq_unique_jobs/client/middleware.rb index a6148b822..007a55a5d 100644 --- a/lib/sidekiq_unique_jobs/client/middleware.rb +++ b/lib/sidekiq_unique_jobs/client/middleware.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'sidekiq_unique_jobs/server/middleware' +require "sidekiq_unique_jobs/server/middleware" module SidekiqUniqueJobs module Client diff --git a/lib/sidekiq_unique_jobs/constants.rb b/lib/sidekiq_unique_jobs/constants.rb index effc7d572..c1d29c941 100644 --- a/lib/sidekiq_unique_jobs/constants.rb +++ b/lib/sidekiq_unique_jobs/constants.rb @@ -1,24 +1,29 @@ # frozen_string_literal: true +# +# Module with constants to avoid string duplication +# +# @author Mikael Henriksson +# module SidekiqUniqueJobs - ARGS_KEY ||= 'args' - AT_KEY ||= 'at' - CLASS_KEY ||= 'class' - JID_KEY ||= 'jid' - LOCK_EXPIRATION_KEY ||= 'lock_expiration' - LOCK_TIMEOUT_KEY ||= 'lock_timeout' - LOG_DUPLICATE_KEY ||= 'log_duplicate_payload' - QUEUE_KEY ||= 'queue' - UNIQUE_ACROSS_QUEUES_KEY ||= 'unique_across_queues' - UNIQUE_ACROSS_WORKERS_KEY ||= 'unique_across_workers' - UNIQUE_ARGS_KEY ||= 'unique_args' - UNIQUE_DIGEST_KEY ||= 'unique_digest' - UNIQUE_KEY ||= 'unique' - UNIQUE_SET ||= 'unique:keys' - LOCK_KEY ||= 'lock' - ON_CONFLICT_KEY ||= 'on_conflict' - UNIQUE_ON_ALL_QUEUES_KEY ||= 'unique_on_all_queues' # TODO: Remove in v6.1 - UNIQUE_PREFIX_KEY ||= 'unique_prefix' - RETRY_SET ||= 'retry' - SCHEDULE_SET ||= 'schedule' + ARGS_KEY ||= "args" + AT_KEY ||= "at" + CLASS_KEY ||= "class" + JID_KEY ||= "jid" + LOCK_EXPIRATION_KEY ||= "lock_expiration" + LOCK_TIMEOUT_KEY ||= "lock_timeout" + LOG_DUPLICATE_KEY ||= "log_duplicate_payload" + QUEUE_KEY ||= "queue" + UNIQUE_ACROSS_QUEUES_KEY ||= "unique_across_queues" + UNIQUE_ACROSS_WORKERS_KEY ||= "unique_across_workers" + UNIQUE_ARGS_KEY ||= "unique_args" + UNIQUE_DIGEST_KEY ||= "unique_digest" + UNIQUE_KEY ||= "unique" + UNIQUE_SET ||= "unique:keys" + LOCK_KEY ||= "lock" + ON_CONFLICT_KEY ||= "on_conflict" + UNIQUE_ON_ALL_QUEUES_KEY ||= "unique_on_all_queues" # TODO: Remove in v6.1 + UNIQUE_PREFIX_KEY ||= "unique_prefix" + RETRY_SET ||= "retry" + SCHEDULE_SET ||= "schedule" end diff --git a/lib/sidekiq_unique_jobs/digests.rb b/lib/sidekiq_unique_jobs/digests.rb index b4368ee56..80f01b096 100644 --- a/lib/sidekiq_unique_jobs/digests.rb +++ b/lib/sidekiq_unique_jobs/digests.rb @@ -6,7 +6,7 @@ module SidekiqUniqueJobs # @author Mikael Henriksson module Digests DEFAULT_COUNT = 1_000 - SCAN_PATTERN = '*' + SCAN_PATTERN = "*" CHUNK_SIZE = 100 include SidekiqUniqueJobs::Logging @@ -25,8 +25,9 @@ def all(pattern: SCAN_PATTERN, count: DEFAULT_COUNT) # Paginate unique digests # # @param [String] pattern a pattern to match with - # @param [Integer] page the current cursor position - # @param [Integer] count the maximum number to match + # @param [Integer] cursor the maximum number to match + # @param [Integer] page_size the current cursor position + # # @return [Array] with unique digests def page(pattern: SCAN_PATTERN, cursor: 0, page_size: 100) redis do |conn| @@ -57,7 +58,7 @@ def del(digest: nil, pattern: nil, count: DEFAULT_COUNT) return delete_by_pattern(pattern, count: count) if pattern return delete_by_digest(digest) if digest - raise ArgumentError, 'either digest or pattern need to be provided' + raise ArgumentError, "either digest or pattern need to be provided" end private diff --git a/lib/sidekiq_unique_jobs/lock/base_lock.rb b/lib/sidekiq_unique_jobs/lock/base_lock.rb index 198af41a3..373ad185d 100644 --- a/lib/sidekiq_unique_jobs/lock/base_lock.rb +++ b/lib/sidekiq_unique_jobs/lock/base_lock.rb @@ -108,14 +108,14 @@ def locksmith def with_cleanup yield rescue Sidekiq::Shutdown - log_info('Sidekiq is shutting down, the job `should` be put back on the queue. Keeping the lock!') + log_info("Sidekiq is shutting down, the job `should` be put back on the queue. Keeping the lock!") raise else unlock_with_callback end def unlock_with_callback - return log_warn('might need to be unlocked manually') unless unlock + return log_warn("might need to be unlocked manually") unless unlock callback_safely item[JID_KEY] @@ -124,7 +124,7 @@ def unlock_with_callback def callback_safely callback&.call rescue StandardError - log_warn('unlocked successfully but the #after_unlock callback failed!') + log_warn("unlocked successfully but the #after_unlock callback failed!") raise end diff --git a/lib/sidekiq_unique_jobs/lock/until_executed.rb b/lib/sidekiq_unique_jobs/lock/until_executed.rb index 6780dc86b..3b5a172be 100644 --- a/lib/sidekiq_unique_jobs/lock/until_executed.rb +++ b/lib/sidekiq_unique_jobs/lock/until_executed.rb @@ -8,7 +8,7 @@ class Lock # # @author Mikael Henriksson class UntilExecuted < BaseLock - OK ||= 'OK' + OK ||= "OK" # Executes in the Sidekiq server process # @yield to the worker class perform method diff --git a/lib/sidekiq_unique_jobs/lock/while_executing.rb b/lib/sidekiq_unique_jobs/lock/while_executing.rb index 3f858fb07..9955253d6 100644 --- a/lib/sidekiq_unique_jobs/lock/while_executing.rb +++ b/lib/sidekiq_unique_jobs/lock/while_executing.rb @@ -11,7 +11,7 @@ class Lock # # @author Mikael Henriksson class WhileExecuting < BaseLock - RUN_SUFFIX ||= ':RUN' + RUN_SUFFIX ||= ":RUN" # @param [Hash] item the Sidekiq job hash # @param [Proc] callback callback to call after unlock diff --git a/lib/sidekiq_unique_jobs/locksmith.rb b/lib/sidekiq_unique_jobs/locksmith.rb index 597dc4a1d..76035d61e 100644 --- a/lib/sidekiq_unique_jobs/locksmith.rb +++ b/lib/sidekiq_unique_jobs/locksmith.rb @@ -133,19 +133,19 @@ def return_token_or_block_value(token) end def available_key - @available_key ||= namespaced_key('AVAILABLE') + @available_key ||= namespaced_key("AVAILABLE") end def exists_key - @exists_key ||= namespaced_key('EXISTS') + @exists_key ||= namespaced_key("EXISTS") end def grabbed_key - @grabbed_key ||= namespaced_key('GRABBED') + @grabbed_key ||= namespaced_key("GRABBED") end def version_key - @version_key ||= namespaced_key('VERSION') + @version_key ||= namespaced_key("VERSION") end def namespaced_key(variable) diff --git a/lib/sidekiq_unique_jobs/logging.rb b/lib/sidekiq_unique_jobs/logging.rb index c79da3c53..05a624369 100644 --- a/lib/sidekiq_unique_jobs/logging.rb +++ b/lib/sidekiq_unique_jobs/logging.rb @@ -51,7 +51,7 @@ def log_fatal(message_or_exception = nil, &block) end def logging_context(middleware_class, job_hash) - digest = job_hash['unique_digest'] + digest = job_hash["unique_digest"] "#{middleware_class} #{"DIG-#{digest}" if digest}" end end diff --git a/lib/sidekiq_unique_jobs/middleware.rb b/lib/sidekiq_unique_jobs/middleware.rb index 3e72aa4bf..9a512331f 100644 --- a/lib/sidekiq_unique_jobs/middleware.rb +++ b/lib/sidekiq_unique_jobs/middleware.rb @@ -1,8 +1,13 @@ # frozen_string_literal: true -require 'sidekiq' +require "sidekiq" module SidekiqUniqueJobs + # + # Provides the sidekiq middleware that makes the gem work + # + # @author Mikael Henriksson + # module Middleware def self.extended(base) base.class_eval do @@ -18,12 +23,12 @@ def configure_middleware def configure_server_middleware Sidekiq.configure_server do |config| config.client_middleware do |chain| - require 'sidekiq_unique_jobs/client/middleware' + require "sidekiq_unique_jobs/client/middleware" chain.add SidekiqUniqueJobs::Client::Middleware end config.server_middleware do |chain| - require 'sidekiq_unique_jobs/server/middleware' + require "sidekiq_unique_jobs/server/middleware" chain.add SidekiqUniqueJobs::Server::Middleware end end @@ -32,7 +37,7 @@ def configure_server_middleware def configure_client_middleware Sidekiq.configure_client do |config| config.client_middleware do |chain| - require 'sidekiq_unique_jobs/client/middleware' + require "sidekiq_unique_jobs/client/middleware" chain.add SidekiqUniqueJobs::Client::Middleware end end diff --git a/lib/sidekiq_unique_jobs/normalizer.rb b/lib/sidekiq_unique_jobs/normalizer.rb index d91f34159..1f3bcff64 100644 --- a/lib/sidekiq_unique_jobs/normalizer.rb +++ b/lib/sidekiq_unique_jobs/normalizer.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'json' +require "json" module SidekiqUniqueJobs # Normalizes hashes by dumping them to json and loading them from json diff --git a/lib/sidekiq_unique_jobs/on_conflict.rb b/lib/sidekiq_unique_jobs/on_conflict.rb index 7dd390a67..41f3376f7 100644 --- a/lib/sidekiq_unique_jobs/on_conflict.rb +++ b/lib/sidekiq_unique_jobs/on_conflict.rb @@ -1,14 +1,19 @@ # frozen_string_literal: true -require_relative 'on_conflict/strategy' -require_relative 'on_conflict/null_strategy' -require_relative 'on_conflict/log' -require_relative 'on_conflict/raise' -require_relative 'on_conflict/reject' -require_relative 'on_conflict/replace' -require_relative 'on_conflict/reschedule' +require_relative "on_conflict/strategy" +require_relative "on_conflict/null_strategy" +require_relative "on_conflict/log" +require_relative "on_conflict/raise" +require_relative "on_conflict/reject" +require_relative "on_conflict/replace" +require_relative "on_conflict/reschedule" module SidekiqUniqueJobs + # + # Provides lock conflict resolutions + # + # @author Mikael Henriksson + # module OnConflict STRATEGIES = { log: OnConflict::Log, diff --git a/lib/sidekiq_unique_jobs/on_conflict/raise.rb b/lib/sidekiq_unique_jobs/on_conflict/raise.rb index 549e6b24e..e4118328c 100644 --- a/lib/sidekiq_unique_jobs/on_conflict/raise.rb +++ b/lib/sidekiq_unique_jobs/on_conflict/raise.rb @@ -10,7 +10,7 @@ class Raise < OnConflict::Strategy # This will cause Sidekiq to retry the job # @raise [SidekiqUniqueJobs::Conflict] def call - fail SidekiqUniqueJobs::Conflict, item + raise SidekiqUniqueJobs::Conflict, item end end end diff --git a/lib/sidekiq_unique_jobs/on_conflict/reject.rb b/lib/sidekiq_unique_jobs/on_conflict/reject.rb index eca10e889..5386730f8 100644 --- a/lib/sidekiq_unique_jobs/on_conflict/reject.rb +++ b/lib/sidekiq_unique_jobs/on_conflict/reject.rb @@ -53,9 +53,9 @@ def deadset def push_to_deadset Sidekiq.redis do |conn| conn.multi do - conn.zadd('dead', current_time, payload) - conn.zremrangebyscore('dead', '-inf', current_time - Sidekiq::DeadSet.timeout) - conn.zremrangebyrank('dead', 0, -Sidekiq::DeadSet.max_jobs) + conn.zadd("dead", current_time, payload) + conn.zremrangebyscore("dead", "-inf", current_time - Sidekiq::DeadSet.timeout) + conn.zremrangebyrank("dead", 0, -Sidekiq::DeadSet.max_jobs) end end end diff --git a/lib/sidekiq_unique_jobs/on_conflict/strategy.rb b/lib/sidekiq_unique_jobs/on_conflict/strategy.rb index 54a0229e3..49761deca 100644 --- a/lib/sidekiq_unique_jobs/on_conflict/strategy.rb +++ b/lib/sidekiq_unique_jobs/on_conflict/strategy.rb @@ -21,7 +21,7 @@ def initialize(item) # Use strategy on conflict # @raise [NotImplementedError] needs to be implemented in child class def call - fail NotImplementedError, 'needs to be implemented in child class' + raise NotImplementedError, "needs to be implemented in child class" end def replace? diff --git a/lib/sidekiq_unique_jobs/options_with_fallback.rb b/lib/sidekiq_unique_jobs/options_with_fallback.rb index ce89de8f4..270f9ef36 100644 --- a/lib/sidekiq_unique_jobs/options_with_fallback.rb +++ b/lib/sidekiq_unique_jobs/options_with_fallback.rb @@ -50,7 +50,7 @@ def lock def lock_class @lock_class ||= begin LOCKS.fetch(lock_type.to_sym) do - fail UnknownLock, "No implementation for `lock: :#{lock_type}`" + raise UnknownLock, "No implementation for `lock: :#{lock_type}`" end end end diff --git a/lib/sidekiq_unique_jobs/scripts.rb b/lib/sidekiq_unique_jobs/scripts.rb index c6f2726e1..5a6002fef 100644 --- a/lib/sidekiq_unique_jobs/scripts.rb +++ b/lib/sidekiq_unique_jobs/scripts.rb @@ -1,15 +1,15 @@ # frozen_string_literal: true -require 'pathname' -require 'digest/sha1' -require 'concurrent/map' +require "pathname" +require "digest/sha1" +require "concurrent/map" module SidekiqUniqueJobs # Interface to dealing with .lua files # # @author Mikael Henriksson module Scripts - LUA_PATHNAME ||= Pathname.new(__FILE__).dirname.join('../../redis').freeze + LUA_PATHNAME ||= Pathname.new(__FILE__).dirname.join("../../redis").freeze SCRIPT_SHAS ||= Concurrent::Map.new include SidekiqUniqueJobs::Connection @@ -64,7 +64,7 @@ def script_sha(conn, file_name) # @param [Symbol] file_name the name of the lua script # @raise [ScriptError] when the error isn't handled def handle_error(ex, file_name) - if ex.message == 'NOSCRIPT No matching script. Please use EVAL.' + if ex.message == "NOSCRIPT No matching script. Please use EVAL." SCRIPT_SHAS.delete(file_name) return yield if block_given? end diff --git a/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb b/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb index 47b575141..b0aea768a 100644 --- a/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb +++ b/lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'sidekiq/api' +require "sidekiq/api" module Sidekiq class SortedEntry diff --git a/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb b/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb new file mode 100644 index 000000000..0f42dd5cb --- /dev/null +++ b/lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +# +# Contains configuration and utility methods that belongs top level +# +# @author Mikael Henriksson +module SidekiqUniqueJobs + include SidekiqUniqueJobs::Connection + + module_function + + Config = Concurrent::MutableStruct.new( + :default_lock_timeout, + :enabled, + :unique_prefix, + :logger, + ) + + # The current configuration (See: {.configure} on how to configure) + def config + # Arguments here need to match the definition of the new class (see above) + @config ||= Config.new( + 0, + true, + "uniquejobs", + Sidekiq.logger, + ) + end + + # The current logger + # @return [Logger] the configured logger + def logger + config.logger + end + + # Set a new logger + # @param [Logger] other a new logger + def logger=(other) + config.logger = other + end + + # Change global configuration while yielding + # @yield control to the caller + def use_config(tmp_config) + raise ::ArgumentError, "#{name}.#{__method__} needs a block" unless block_given? + + old_config = config.to_h + configure(tmp_config) + yield + configure(old_config) + end + + # Configure the gem + # + # This is usually called once at startup of an application + # @param [Hash] options global gem options + # @option options [Integer] :default_lock_timeout (default is 0) + # @option options [true,false] :enabled (default is true) + # @option options [String] :unique_prefix (default is 'uniquejobs') + # @option options [Logger] :logger (default is Sidekiq.logger) + # @yield control to the caller when given block + def configure(options = {}) + if block_given? + yield config + else + options.each do |key, val| + config.send("#{key}=", val) + end + end + end + + def redis_version + @redis_version ||= redis { |conn| conn.info("server")["redis_version"] } + end +end diff --git a/lib/sidekiq_unique_jobs/testing.rb b/lib/sidekiq_unique_jobs/testing.rb index 19e88bd4a..d90dd9f53 100644 --- a/lib/sidekiq_unique_jobs/testing.rb +++ b/lib/sidekiq_unique_jobs/testing.rb @@ -2,8 +2,8 @@ # :nocov: -require 'sidekiq' -require 'sidekiq/testing' +require "sidekiq" +require "sidekiq/testing" module Sidekiq def self.use_options(tmp_config = {}) @@ -52,7 +52,7 @@ class << self module Testing def clear_all_ext clear_all_orig - SidekiqUniqueJobs::Util.del('*', 1000) + SidekiqUniqueJobs::Util.del("*", 1000) end end end diff --git a/lib/sidekiq_unique_jobs/timeout.rb b/lib/sidekiq_unique_jobs/timeout.rb index af45d8b16..fc93e800b 100644 --- a/lib/sidekiq_unique_jobs/timeout.rb +++ b/lib/sidekiq_unique_jobs/timeout.rb @@ -5,4 +5,4 @@ module Timeout end end -require 'sidekiq_unique_jobs/timeout/calculator' +require "sidekiq_unique_jobs/timeout/calculator" diff --git a/lib/sidekiq_unique_jobs/unique_args.rb b/lib/sidekiq_unique_jobs/unique_args.rb index df7ca7f58..5ae9788a4 100644 --- a/lib/sidekiq_unique_jobs/unique_args.rb +++ b/lib/sidekiq_unique_jobs/unique_args.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'digest' -require 'sidekiq_unique_jobs/normalizer' +require "digest" +require "sidekiq_unique_jobs/normalizer" module SidekiqUniqueJobs # Handles uniqueness of sidekiq arguments diff --git a/lib/sidekiq_unique_jobs/util.rb b/lib/sidekiq_unique_jobs/util.rb index d718b2db0..83bc93178 100644 --- a/lib/sidekiq_unique_jobs/util.rb +++ b/lib/sidekiq_unique_jobs/util.rb @@ -7,7 +7,7 @@ module SidekiqUniqueJobs # @author Mikael Henriksson module Util DEFAULT_COUNT = 1_000 - SCAN_PATTERN = '*' + SCAN_PATTERN = "*" include SidekiqUniqueJobs::Logging include SidekiqUniqueJobs::Connection @@ -44,7 +44,7 @@ def keys_with_ttl(pattern = SCAN_PATTERN, count = DEFAULT_COUNT) # @param [Integer] count the maximum number of keys to delete # @return [Integer] the number of keys deleted def del(pattern = SCAN_PATTERN, count = 0) - raise ArgumentError, 'Please provide a number of keys to delete greater than zero' if count.zero? + raise ArgumentError, "Please provide a number of keys to delete greater than zero" if count.zero? pattern = suffix(pattern) @@ -91,7 +91,7 @@ def prefix(key) end def suffix(key) - return "#{key}*" unless key.end_with?(':*') + return "#{key}*" unless key.end_with?(":*") key end diff --git a/lib/sidekiq_unique_jobs/version.rb b/lib/sidekiq_unique_jobs/version.rb index 1d9f6aabc..b6acaa099 100644 --- a/lib/sidekiq_unique_jobs/version.rb +++ b/lib/sidekiq_unique_jobs/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module SidekiqUniqueJobs - VERSION = '6.0.8' + VERSION = "6.0.8" end diff --git a/lib/sidekiq_unique_jobs/web.rb b/lib/sidekiq_unique_jobs/web.rb index 2e363cb5a..d8c38928c 100644 --- a/lib/sidekiq_unique_jobs/web.rb +++ b/lib/sidekiq_unique_jobs/web.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true begin - require 'sidekiq/web' + require "sidekiq/web" rescue LoadError # rubocop:disable Lint/HandleExceptions # client-only usage end -require_relative 'web/helpers' +require_relative "web/helpers" module SidekiqUniqueJobs # Utility module to help manage unique keys in redis. @@ -19,9 +19,9 @@ def self.registered(app) # rubocop:disable Metrics/MethodLength include Web::Helpers end - app.get '/unique_digests' do - @filter = params[:filter] || '*' - @filter = '*' if @filter == '' + app.get "/unique_digests" do + @filter = params[:filter] || "*" + @filter = "*" if @filter == "" @count = (params[:count] || 100).to_i @current_cursor = params[:cursor] @prev_cursor = params[:prev_cursor] @@ -31,14 +31,14 @@ def self.registered(app) # rubocop:disable Metrics/MethodLength erb(unique_template(:unique_digests)) end - app.get '/unique_digests/:digest' do + app.get "/unique_digests/:digest" do @digest = params[:digest] @unique_keys = Util.keys("#{@digest}*", 1000) erb(unique_template(:unique_digest)) end - app.get '/unique_digests/:digest/delete' do + app.get "/unique_digests/:digest/delete" do Digests.del(digest: params[:digest]) redirect_to :unique_digests end @@ -48,6 +48,6 @@ def self.registered(app) # rubocop:disable Metrics/MethodLength if defined?(Sidekiq::Web) Sidekiq::Web.register SidekiqUniqueJobs::Web - Sidekiq::Web.tabs['Unique Digests'] = 'unique_digests' + Sidekiq::Web.tabs["Unique Digests"] = "unique_digests" # Sidekiq::Web.settings.locales << File.join(File.dirname(__FILE__), 'locales') end diff --git a/lib/sidekiq_unique_jobs/web/helpers.rb b/lib/sidekiq_unique_jobs/web/helpers.rb index ddda54d74..5e9f068c3 100644 --- a/lib/sidekiq_unique_jobs/web/helpers.rb +++ b/lib/sidekiq_unique_jobs/web/helpers.rb @@ -3,7 +3,7 @@ module SidekiqUniqueJobs module Web module Helpers - VIEW_PATH = File.expand_path('../web/views', __dir__) + VIEW_PATH = File.expand_path("../web/views", __dir__) def unique_template(name) File.open(File.join(VIEW_PATH, "#{name}.erb")).read @@ -21,7 +21,7 @@ def cparams(options) next unless SAFE_CPARAMS.include?(key) "#{key}=#{CGI.escape(value.to_s)}" - end.compact.join('&') + end.compact.join("&") end def redirect_to(subpath) diff --git a/lib/tasks/changelog.rake b/lib/tasks/changelog.rake new file mode 100644 index 000000000..3d03d2e92 --- /dev/null +++ b/lib/tasks/changelog.rake @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +desc "Generate a Changelog" +task :changelog do + # rubocop:disable Style/MutableConstant + CHANGELOG_CMD ||= %w[ + github_changelog_generator + -u + mhenrixon + -p + sidekiq-unique-jobs + --no-verbose + --token + ] + ADD_CHANGELOG_CMD ||= "git add --all" + COMMIT_CHANGELOG_CMD ||= "git commit -a -m 'Update changelog'" + # rubocop:enable Style/MutableConstant + + sh("git checkout master") + sh(*CHANGELOG_CMD.push(ENV["CHANGELOG_GITHUB_TOKEN"])) + sh(ADD_CHANGELOG_CMD) + sh(COMMIT_CHANGELOG_CMD) +end diff --git a/rails_example/Gemfile b/rails_example/Gemfile index 5e06e0d96..5e1aaf6ab 100644 --- a/rails_example/Gemfile +++ b/rails_example/Gemfile @@ -1,27 +1,27 @@ # frozen_string_literal: true -source 'https://rubygems.org' +source "https://rubygems.org" -ruby '2.5.1' +ruby "2.5.3" -gem 'bigdecimal' -gem 'json' -gem 'pg' -gem 'puma' -gem 'rack-protection' -gem 'rails', '~> 5.2' -gem 'sidekiq' -gem 'sidekiq-unique-jobs', path: '..' -gem 'sinatra' -gem 'slim-rails' +gem "bigdecimal" +gem "json" +gem "pg" +gem "puma" +gem "rack-protection" +gem "rails", "~> 5.2" +gem "sidekiq" +gem "sidekiq-unique-jobs", path: ".." +gem "sinatra" +gem "slim-rails" group :development, :test do - gem 'capybara' - gem 'dotenv-rails' - gem 'factory_bot_rails' - gem 'fuubar' - gem 'pry-rails' - gem 'pry-byebug' - gem 'rspec-eventually' - gem 'rspec-rails' + gem "capybara" + gem "dotenv-rails" + gem "factory_bot_rails" + gem "fuubar" + gem "pry-byebug" + gem "pry-rails" + gem "rspec-eventually" + gem "rspec-rails" end diff --git a/rails_example/Rakefile b/rails_example/Rakefile index e51cf0e17..dbf84da93 100644 --- a/rails_example/Rakefile +++ b/rails_example/Rakefile @@ -3,6 +3,6 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path('config/application', __dir__) +require File.expand_path("config/application", __dir__) Rails.application.load_tasks diff --git a/rails_example/bin/bundle b/rails_example/bin/bundle index 2dbb71769..5015ba6f8 100755 --- a/rails_example/bin/bundle +++ b/rails_example/bin/bundle @@ -1,5 +1,5 @@ #!/usr/bin/env ruby # frozen_string_literal: true -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) -load Gem.bin_path('bundler', 'bundle') +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) +load Gem.bin_path("bundler", "bundle") diff --git a/rails_example/bin/check_or_setup_db b/rails_example/bin/check_or_setup_db index 22810cb9b..00eb2b5c5 100755 --- a/rails_example/bin/check_or_setup_db +++ b/rails_example/bin/check_or_setup_db @@ -8,14 +8,14 @@ # We are using this custom script instead of running the # `rake db:version || rake db:setup` commands, as that currently leaves a # couple of small ruby zombie processes running in the app container: -require 'rubygems' -require 'rake' -require 'bundler' +require "rubygems" +require "rake" +require "bundler" Bundler.setup(:default) -require 'active_record' -require 'pg' +require "active_record" +require "pg" exit begin connection_tries ||= 3 @@ -24,21 +24,21 @@ exit begin rescue PG::ConnectionBad unless (connection_tries -= 1).zero? puts "Retrying DB connection #{connection_tries} more times..." - sleep ENV.fetch('APP_SETUP_WAIT', '5').to_i + sleep ENV.fetch("APP_SETUP_WAIT", "5").to_i retry end 1 rescue ActiveRecord::NoDatabaseError, ActiveRecord::AdapterNotSpecified include ActiveRecord::Tasks # rubocop:disable Style/MixinUsage - DatabaseTasks.root = File.expand_path '..', __dir__ - DatabaseTasks.db_dir = File.join DatabaseTasks.root, 'db' - DatabaseTasks.env = ENV.fetch 'ENV', ENV.fetch('RAILS_ENV', 'development') + DatabaseTasks.root = File.expand_path "..", __dir__ + DatabaseTasks.db_dir = File.join DatabaseTasks.root, "db" + DatabaseTasks.env = ENV.fetch "ENV", ENV.fetch("RAILS_ENV", "development") # The App database seeder: DatabaseTasks.seed_loader = (Class.new do def load_seed - seed_file_path = File.join DatabaseTasks.db_dir, 'seeds.rb' + seed_file_path = File.join DatabaseTasks.db_dir, "seeds.rb" raise "Seed file '#{seed_file_path}' does not exist" unless File.file?(seed_file_path) load seed_file_path @@ -46,8 +46,8 @@ exit begin end).new # Add model dirs to the autoload_paths for the seeder to run smoothly: - ActiveSupport::Dependencies.autoload_paths << File.join(DatabaseTasks.root, 'app', 'models', 'concerns') - ActiveSupport::Dependencies.autoload_paths << File.join(DatabaseTasks.root, 'app', 'models') + ActiveSupport::Dependencies.autoload_paths << File.join(DatabaseTasks.root, "app", "models", "concerns") + ActiveSupport::Dependencies.autoload_paths << File.join(DatabaseTasks.root, "app", "models") return 2 unless DatabaseTasks.create_current return 3 unless DatabaseTasks.load_schema_current diff --git a/rails_example/bin/rails b/rails_example/bin/rails index a31728ab9..22f2d8dee 100755 --- a/rails_example/bin/rails +++ b/rails_example/bin/rails @@ -1,6 +1,6 @@ #!/usr/bin/env ruby # frozen_string_literal: true -APP_PATH = File.expand_path('../config/application', __dir__) -require_relative '../config/boot' -require 'rails/commands' +APP_PATH = File.expand_path("../config/application", __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/rails_example/bin/rake b/rails_example/bin/rake index c19995500..e436ea54a 100755 --- a/rails_example/bin/rake +++ b/rails_example/bin/rake @@ -1,6 +1,6 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require_relative '../config/boot' -require 'rake' +require_relative "../config/boot" +require "rake" Rake.application.run diff --git a/rails_example/bin/setup b/rails_example/bin/setup index fdb13c5ce..78380f59a 100755 --- a/rails_example/bin/setup +++ b/rails_example/bin/setup @@ -1,11 +1,11 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require 'fileutils' +require "fileutils" include FileUtils # rubocop:disable Style/MixinUsage # path to your application root. -APP_ROOT = File.expand_path('..', __dir__) +APP_ROOT = File.expand_path("..", __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") @@ -15,9 +15,9 @@ chdir APP_ROOT do # This script is a starting point to setup your application. # Add necessary setup steps to this file. - puts '== Installing dependencies ==' - system! 'gem install bundler --conservative' - system('bundle check') || system!('bundle install') + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") # Install JavaScript dependencies if using Yarn # system('bin/yarn') @@ -28,11 +28,11 @@ chdir APP_ROOT do # end puts "\n== Preparing database ==" - system! 'bin/rails db:setup' + system! "bin/rails db:setup" puts "\n== Removing old logs and tempfiles ==" - system! 'bin/rails log:clear tmp:clear' + system! "bin/rails log:clear tmp:clear" puts "\n== Restarting application server ==" - system! 'bin/rails restart' + system! "bin/rails restart" end diff --git a/rails_example/bin/update b/rails_example/bin/update index 73dd1c3f7..88bc67c03 100755 --- a/rails_example/bin/update +++ b/rails_example/bin/update @@ -1,11 +1,11 @@ #!/usr/bin/env ruby # frozen_string_literal: true -require 'fileutils' +require "fileutils" include FileUtils # rubocop:disable Style/MixinUsage # path to your application root. -APP_ROOT = File.expand_path('..', __dir__) +APP_ROOT = File.expand_path("..", __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") @@ -15,19 +15,19 @@ chdir APP_ROOT do # This script is a way to update your development environment automatically. # Add necessary update steps to this file. - puts '== Installing dependencies ==' - system! 'gem install bundler --conservative' - system('bundle check') || system!('bundle install') + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") # Install JavaScript dependencies if using Yarn # system('bin/yarn') puts "\n== Updating database ==" - system! 'bin/rails db:migrate' + system! "bin/rails db:migrate" puts "\n== Removing old logs and tempfiles ==" - system! 'bin/rails log:clear tmp:clear' + system! "bin/rails log:clear tmp:clear" puts "\n== Restarting application server ==" - system! 'bin/rails restart' + system! "bin/rails restart" end diff --git a/rails_example/spec/factories/posts.rb b/rails_example/spec/factories/posts.rb index 6f62863d5..a0e0a6ecc 100644 --- a/rails_example/spec/factories/posts.rb +++ b/rails_example/spec/factories/posts.rb @@ -2,9 +2,9 @@ FactoryBot.define do factory :post do - title 'MyString' - body 'MyText' - excerpt 'MyString' - read_count 1 + title { 'MyString' } + body { 'MyText' } + excerpt { 'MyString' } + read_count { 1 } end end diff --git a/rails_example/spec/spec_helper.rb b/rails_example/spec/spec_helper.rb index d6befd16a..0cefc7bb1 100644 --- a/rails_example/spec/spec_helper.rb +++ b/rails_example/spec/spec_helper.rb @@ -15,7 +15,7 @@ config.shared_context_metadata_behavior = :apply_to_host_groups config.filter_run_when_matching :focus - config.example_status_persistence_file_path = 'spec/examples.txt' + config.example_status_persistence_file_path = ".rspec_status" # config.disable_monkey_patching! config.default_formatter = 'doc' if config.files_to_run.one? diff --git a/sidekiq-unique-jobs.gemspec b/sidekiq-unique-jobs.gemspec index 3cf57eb28..0bc08ff8e 100644 --- a/sidekiq-unique-jobs.gemspec +++ b/sidekiq-unique-jobs.gemspec @@ -1,42 +1,48 @@ # frozen_string_literal: true -lib = File.expand_path("../lib", __FILE__) +lib = File.expand_path("lib", __dir__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'sidekiq_unique_jobs/version' +require "sidekiq_unique_jobs/version" Gem::Specification.new do |spec| - spec.name = 'sidekiq-unique-jobs' + spec.name = "sidekiq-unique-jobs" spec.version = SidekiqUniqueJobs::VERSION - spec.authors = ['Mikael Henriksson'] - spec.email = ['mikael@zoolutions.se'] - - spec.summary = 'Uniqueness for Sidekiq Jobs' - spec.description = 'Handles various types of unique jobs for Sidekiq' - spec.homepage = 'https://github.com/mhenrixon/sidekiq-unique-jobs' - spec.license = 'MIT' + spec.authors = ["Mikael Henriksson"] + spec.email = ["mikael@zoolutions.se"] + + spec.summary = "Prevent duplicate jobs in Sidekiq" + spec.description = "An attempt to prevent simultaneous Sidekiq jobs with the same unique arguments to run" + spec.homepage = "https://mhenrixon.github.com/sidekiq-unique-jobs" + spec.license = "MIT" + + if spec.respond_to?(:metadata) + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = "https://github.com/mhenrixon/stub_requests" + spec.metadata["changelog_uri"] = "https://github.com/mhenrixon/stub_requests/CHANGELOG.md" + else + raise "RubyGems 2.0 or newer is required to protect against " \ + "public gem pushes." + end - spec.bindir = 'bin' + spec.bindir = "bin" spec.executables = %w[uniquejobs] - spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do + spec.files = Dir.chdir(File.expand_path(__dir__)) do `git ls-files -z`.split("\x0").reject do |file| file.match(%r{^(test|spec|features|gemfiles|pkg|rails_example|tmp)/}) end end - spec.require_paths = ['lib'] - spec.add_dependency 'concurrent-ruby', '~> 1.0', '>= 1.0.5' - spec.add_dependency 'sidekiq', '>= 4.0', '< 6.0' - spec.add_dependency 'thor', '~> 0' - - spec.add_development_dependency 'bundler', '>= 1.16' - spec.add_development_dependency 'rspec', '~> 3.7' - spec.add_development_dependency 'rake', '~> 12.3' - spec.add_development_dependency 'timecop', '~> 0.9' - spec.add_development_dependency 'yard', '~> 0.9' - spec.add_development_dependency 'gem-release', '~> 1.0' - spec.add_development_dependency 'awesome_print', '~> 1.8' - spec.add_development_dependency 'rack-test' - spec.add_development_dependency 'sinatra' + spec.require_paths = ["lib"] + spec.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.5" + spec.add_dependency "sidekiq", ">= 4.0", "< 6.0" + spec.add_dependency "thor", "~> 0" + + spec.add_development_dependency "bundler", ">= 2.0" + spec.add_development_dependency "rack-test" + spec.add_development_dependency "rake", "~> 12.3" + spec.add_development_dependency "rspec", "~> 3.7" + spec.add_development_dependency "sinatra" + spec.add_development_dependency "timecop", "~> 0.9" end diff --git a/spec/examples/another_unique_job_spec.rb b/spec/examples/another_unique_job_spec.rb index 44f6940b0..ca9187adf 100644 --- a/spec/examples/another_unique_job_spec.rb +++ b/spec/examples/another_unique_job_spec.rb @@ -1,20 +1,19 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe AnotherUniqueJob, redis: :redis do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :working2, - 'retry' => 1, - 'backtrace' => 10, - 'lock' => :until_executed, + "queue" => :working2, + "retry" => 1, + "backtrace" => 10, + "lock" => :until_executed, } end end - it_behaves_like 'a performing worker', splat_arguments: false do + it_behaves_like "a performing worker", splat_arguments: false do let(:args) { %w[one two] } end end diff --git a/spec/examples/custom_queue_job_spec.rb b/spec/examples/custom_queue_job_spec.rb index 8fabd1427..d10db86a6 100644 --- a/spec/examples/custom_queue_job_spec.rb +++ b/spec/examples/custom_queue_job_spec.rb @@ -1,18 +1,17 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe CustomQueueJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :customqueue, - 'retry' => true, + "queue" => :customqueue, + "retry" => true, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { %w[one two] } end end diff --git a/spec/examples/custom_queue_job_with_filter_method_spec.rb b/spec/examples/custom_queue_job_with_filter_method_spec.rb index 981000dd8..200e82993 100644 --- a/spec/examples/custom_queue_job_with_filter_method_spec.rb +++ b/spec/examples/custom_queue_job_with_filter_method_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe CustomQueueJobWithFilterMethod do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :customqueue, - 'retry' => true, - 'lock' => :until_executed, - 'unique_args' => :args_filter, + "queue" => :customqueue, + "retry" => true, + "lock" => :until_executed, + "unique_args" => :args_filter, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { %w[one two] } end end diff --git a/spec/examples/custom_queue_job_with_filter_proc_spec.rb b/spec/examples/custom_queue_job_with_filter_proc_spec.rb index be664a954..96b9a41fa 100644 --- a/spec/examples/custom_queue_job_with_filter_proc_spec.rb +++ b/spec/examples/custom_queue_job_with_filter_proc_spec.rb @@ -1,20 +1,19 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe CustomQueueJobWithFilterProc do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :customqueue, - 'retry' => true, - 'lock' => :until_expired, - 'unique_args' => a_kind_of(Proc), + "queue" => :customqueue, + "retry" => true, + "lock" => :until_expired, + "unique_args" => a_kind_of(Proc), } end end - it_behaves_like 'a performing worker' do - let(:args) { [1, 'random' => rand, 'name' => 'foobar'] } + it_behaves_like "a performing worker" do + let(:args) { [1, "random" => rand, "name" => "foobar"] } end end diff --git a/spec/examples/expiring_job_spec.rb b/spec/examples/expiring_job_spec.rb index 1d71150a9..fdd65e1e0 100644 --- a/spec/examples/expiring_job_spec.rb +++ b/spec/examples/expiring_job_spec.rb @@ -1,85 +1,84 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe ExpiringJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'lock_expiration' => 600, - 'retry' => true, - 'lock' => :until_executed, + "lock_expiration" => 600, + "retry" => true, + "lock" => :until_executed, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { [1, 2] } end - describe 'client middleware' do - context 'when job is delayed' do + describe "client middleware" do + context "when job is delayed" do before { described_class.perform_in(60, 1, 2) } - it 'rejects new scheduled jobs' do - expect(1).to be_enqueued_in('customqueue') + it "rejects new scheduled jobs" do + expect(1).to be_enqueued_in("customqueue") described_class.perform_in(3600, 1, 2) - expect(1).to be_enqueued_in('customqueue') + expect(1).to be_enqueued_in("customqueue") expect(1).to be_scheduled_at(Time.now.to_f + 2 * 60) end - it 'rejects new jobs' do + it "rejects new jobs" do described_class.perform_async(1, 2) - expect(1).to be_enqueued_in('customqueue') + expect(1).to be_enqueued_in("customqueue") end - it 'allows duplicate messages to different queues' do - expect(1).to be_enqueued_in('customqueue2') - with_sidekiq_options_for(described_class, queue: 'customqueue2') do + it "allows duplicate messages to different queues" do + expect(1).to be_enqueued_in("customqueue2") + with_sidekiq_options_for(described_class, queue: "customqueue2") do described_class.perform_async(1, 2) - expect(1).to be_enqueued_in('customqueue2') + expect(1).to be_enqueued_in("customqueue2") end end - it 'sets keys to expire as per configuration' do - lock_expiration = described_class.get_sidekiq_options['lock_expiration'] + it "sets keys to expire as per configuration" do + lock_expiration = described_class.get_sidekiq_options["lock_expiration"] unique_keys.each do |key| - next if key.end_with?(':GRABBED') + next if key.end_with?(":GRABBED") expect(ttl(key)).to be_within(1).of(lock_expiration + 60) end end end - context 'when job is pushed' do + context "when job is pushed" do before { described_class.perform_async(1, 2) } - it 'rejects new scheduled jobs' do - expect(1).to be_enqueued_in('customqueue') + it "rejects new scheduled jobs" do + expect(1).to be_enqueued_in("customqueue") described_class.perform_in(60, 1, 2) - expect(1).to be_enqueued_in('customqueue') + expect(1).to be_enqueued_in("customqueue") expect(0).to be_scheduled_at(Time.now.to_f + 2 * 60) end - it 'rejects new jobs' do - expect(1).to be_enqueued_in('customqueue') + it "rejects new jobs" do + expect(1).to be_enqueued_in("customqueue") described_class.perform_async(1, 2) - expect(1).to be_enqueued_in('customqueue') + expect(1).to be_enqueued_in("customqueue") end - it 'allows duplicate messages to different queues' do - expect(1).to be_enqueued_in('customqueue') - expect(0).to be_enqueued_in('customqueue2') - with_sidekiq_options_for(described_class, queue: 'customqueue2') do + it "allows duplicate messages to different queues" do + expect(1).to be_enqueued_in("customqueue") + expect(0).to be_enqueued_in("customqueue2") + with_sidekiq_options_for(described_class, queue: "customqueue2") do described_class.perform_async(1, 2) - expect(1).to be_enqueued_in('customqueue2') + expect(1).to be_enqueued_in("customqueue2") end end - it 'sets keys to expire as per configuration' do - lock_expiration = described_class.get_sidekiq_options['lock_expiration'] + it "sets keys to expire as per configuration" do + lock_expiration = described_class.get_sidekiq_options["lock_expiration"] unique_keys.each do |key| - next if key.end_with?(':GRABBED') + next if key.end_with?(":GRABBED") expect(ttl(key)).to be_within(1).of(lock_expiration) end diff --git a/spec/examples/inline_worker_spec.rb b/spec/examples/inline_worker_spec.rb index b3b949c8c..8d3398736 100644 --- a/spec/examples/inline_worker_spec.rb +++ b/spec/examples/inline_worker_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe InlineWorker do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'lock_timeout' => 5, - 'retry' => true, - 'lock' => :while_executing, + "lock_timeout" => 5, + "retry" => true, + "lock" => :while_executing, } end end - it_behaves_like 'a performing worker' do - let(:args) { 'one' } + it_behaves_like "a performing worker" do + let(:args) { "one" } end end diff --git a/spec/examples/just_a_worker_spec.rb b/spec/examples/just_a_worker_spec.rb index e642cc85e..43383f7c0 100644 --- a/spec/examples/just_a_worker_spec.rb +++ b/spec/examples/just_a_worker_spec.rb @@ -1,18 +1,17 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe JustAWorker do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :testqueue, - 'retry' => true, - 'lock' => :until_executed, + "queue" => :testqueue, + "retry" => true, + "lock" => :until_executed, } end end - it_behaves_like 'a performing worker' do - let(:args) { { 'test' => 1 } } + it_behaves_like "a performing worker" do + let(:args) { { "test" => 1 } } end end diff --git a/spec/examples/long_running_job_spec.rb b/spec/examples/long_running_job_spec.rb index 95d835d90..4e11b27f4 100644 --- a/spec/examples/long_running_job_spec.rb +++ b/spec/examples/long_running_job_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe LongRunningJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :customqueue, - 'retry' => 10, - 'lock' => :until_and_while_executing, - 'lock_expiration' => 7_200, + "queue" => :customqueue, + "retry" => 10, + "lock" => :until_and_while_executing, + "lock_expiration" => 7_200, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { %w[one two] } end end diff --git a/spec/examples/main_job_spec.rb b/spec/examples/main_job_spec.rb index 26190e91c..136af20b5 100644 --- a/spec/examples/main_job_spec.rb +++ b/spec/examples/main_job_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe MainJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'log_duplicate_payload' => true, - 'queue' => :customqueue, - 'retry' => true, - 'lock' => :until_executed, + "log_duplicate_payload" => true, + "queue" => :customqueue, + "retry" => true, + "lock" => :until_executed, } end end - it_behaves_like 'a performing worker' do - let(:args) { 'one' } + it_behaves_like "a performing worker" do + let(:args) { "one" } end end diff --git a/spec/examples/my_job_spec.rb b/spec/examples/my_job_spec.rb index 50a9609ba..99fd4b6f6 100644 --- a/spec/examples/my_job_spec.rb +++ b/spec/examples/my_job_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe MyJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'backtrace' => 10, - 'queue' => :working, - 'retry' => 1, + "backtrace" => 10, + "queue" => :working, + "retry" => 1, } end end - it_behaves_like 'a performing worker' do - let(:args) { 'one' } + it_behaves_like "a performing worker" do + let(:args) { "one" } end end diff --git a/spec/examples/my_unique_job_spec.rb b/spec/examples/my_unique_job_spec.rb index b679e64dc..0bd6d45bb 100644 --- a/spec/examples/my_unique_job_spec.rb +++ b/spec/examples/my_unique_job_spec.rb @@ -1,76 +1,75 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe MyUniqueJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'lock' => :until_executed, - 'lock_expiration' => 7_200, - 'queue' => :customqueue, - 'retry' => 10, + "lock" => :until_executed, + "lock_expiration" => 7_200, + "queue" => :customqueue, + "retry" => 10, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { %w[one two] } end - describe 'client middleware', redis: :redis do - context 'when job is delayed' do + describe "client middleware", redis: :redis do + context "when job is delayed" do before { described_class.perform_in(3600, 1, 2) } - it 'rejects new scheduled jobs' do - expect(1).to be_enqueued_in('customqueue') + it "rejects new scheduled jobs" do + expect(1).to be_enqueued_in("customqueue") described_class.perform_in(3600, 1, 2) described_class.perform_in(3600, 1, 2) described_class.perform_in(3600, 1, 2) - expect(1).to be_enqueued_in('customqueue') - expect(1).to be_enqueued_in('schedule') + expect(1).to be_enqueued_in("customqueue") + expect(1).to be_enqueued_in("schedule") expect(schedule_count).to eq(1) expect(1).to be_scheduled_at(Time.now.to_f + 2 * 3600) end - it 'rejects new jobs' do + it "rejects new jobs" do described_class.perform_async(1, 2) - expect(1).to be_enqueued_in('customqueue') + expect(1).to be_enqueued_in("customqueue") end - it 'allows duplicate messages to different queues' do - expect(1).to be_enqueued_in('customqueue2') - with_sidekiq_options_for(described_class, queue: 'customqueue2') do + it "allows duplicate messages to different queues" do + expect(1).to be_enqueued_in("customqueue2") + with_sidekiq_options_for(described_class, queue: "customqueue2") do described_class.perform_async(1, 2) - expect(1).to be_enqueued_in('customqueue2') + expect(1).to be_enqueued_in("customqueue2") end end end - context 'when job is pushed' do + context "when job is pushed" do before { described_class.perform_async(1, 2) } - it 'rejects new scheduled jobs' do - expect(1).to be_enqueued_in('customqueue') + it "rejects new scheduled jobs" do + expect(1).to be_enqueued_in("customqueue") described_class.perform_in(60, 1, 2) - expect(1).to be_enqueued_in('customqueue') + expect(1).to be_enqueued_in("customqueue") expect(0).to be_scheduled_at(Time.now.to_f + 2 * 60) end - it 'rejects new jobs' do - expect(1).to be_enqueued_in('customqueue') + it "rejects new jobs" do + expect(1).to be_enqueued_in("customqueue") described_class.perform_async(1, 2) - expect(1).to be_enqueued_in('customqueue') + expect(1).to be_enqueued_in("customqueue") end - it 'allows duplicate messages to different queues' do - expect(1).to be_enqueued_in('customqueue') - expect(0).to be_enqueued_in('customqueue2') + it "allows duplicate messages to different queues" do + expect(1).to be_enqueued_in("customqueue") + expect(0).to be_enqueued_in("customqueue2") - with_sidekiq_options_for(described_class, queue: 'customqueue2') do + with_sidekiq_options_for(described_class, queue: "customqueue2") do described_class.perform_async(1, 2) - expect(1).to be_enqueued_in('customqueue2') + expect(1).to be_enqueued_in("customqueue2") end end end diff --git a/spec/examples/my_unique_job_with_filter_method_spec.rb b/spec/examples/my_unique_job_with_filter_method_spec.rb index ec2d98954..bb3c5e1ca 100644 --- a/spec/examples/my_unique_job_with_filter_method_spec.rb +++ b/spec/examples/my_unique_job_with_filter_method_spec.rb @@ -1,29 +1,28 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe MyUniqueJobWithFilterMethod do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'backtrace' => true, - 'queue' => :customqueue, - 'retry' => true, - 'lock' => :until_executed, - 'unique_args' => :filtered_args, + "backtrace" => true, + "queue" => :customqueue, + "retry" => true, + "lock" => :until_executed, + "unique_args" => :filtered_args, } end end - it_behaves_like 'a performing worker' do - let(:args) { ['hundred', 'type' => 'extremely unique', 'id' => 44] } + it_behaves_like "a performing worker" do + let(:args) { ["hundred", "type" => "extremely unique", "id" => 44] } end - describe '.filtered_args' do + describe ".filtered_args" do subject { described_class.filtered_args(args) } - let(:args) { ['two', 'type' => 'very unique', 'id' => 4] } + let(:args) { ["two", "type" => "very unique", "id" => 4] } - it { is_expected.to eq(['two', 'very unique']) } + it { is_expected.to eq(["two", "very unique"]) } end end diff --git a/spec/examples/my_unique_job_with_filter_proc_spec.rb b/spec/examples/my_unique_job_with_filter_proc_spec.rb index fb3173f24..29ab73bcc 100644 --- a/spec/examples/my_unique_job_with_filter_proc_spec.rb +++ b/spec/examples/my_unique_job_with_filter_proc_spec.rb @@ -1,27 +1,26 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe MyUniqueJobWithFilterProc do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'backtrace' => true, - 'queue' => :customqueue, - 'retry' => true, - 'lock' => :until_executed, + "backtrace" => true, + "queue" => :customqueue, + "retry" => true, + "lock" => :until_executed, } end end - it_behaves_like 'a performing worker' do - let(:args) { ['one', 'type' => 'unique', 'id' => 2] } + it_behaves_like "a performing worker" do + let(:args) { ["one", "type" => "unique", "id" => 2] } end - describe 'unique_args' do - subject(:unique_args) { described_class.get_sidekiq_options['unique_args'].call(args) } + describe "unique_args" do + subject(:unique_args) { described_class.get_sidekiq_options["unique_args"].call(args) } - let(:args) { ['one', 'type' => 'unique', 'id' => 2] } + let(:args) { ["one", "type" => "unique", "id" => 2] } it { is_expected.to eq(%w[one unique]) } end diff --git a/spec/examples/notify_worker_spec.rb b/spec/examples/notify_worker_spec.rb index af4931a6d..ff6029239 100644 --- a/spec/examples/notify_worker_spec.rb +++ b/spec/examples/notify_worker_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe NotifyWorker do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :notify_worker, - 'retry' => true, - 'lock' => :until_executed, + "queue" => :notify_worker, + "retry" => true, + "lock" => :until_executed, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { %w[one two] } end end diff --git a/spec/examples/plain_class_spec.rb b/spec/examples/plain_class_spec.rb index 9cc957ed8..f6083b106 100644 --- a/spec/examples/plain_class_spec.rb +++ b/spec/examples/plain_class_spec.rb @@ -1,21 +1,20 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe PlainClass do - describe '.run' do + describe ".run" do subject { described_class.run(arg) } - let(:arg) { 'argument' } + let(:arg) { "argument" } - it { is_expected.to eq(['argument']) } + it { is_expected.to eq(["argument"]) } end - describe '#run' do + describe "#run" do subject { described_class.new.run(arg) } - let(:arg) { 'another argument' } + let(:arg) { "another argument" } - it { is_expected.to eq(['another argument']) } + it { is_expected.to eq(["another argument"]) } end end diff --git a/spec/examples/simple_worker_spec.rb b/spec/examples/simple_worker_spec.rb index e055d05cf..a3555ad44 100644 --- a/spec/examples/simple_worker_spec.rb +++ b/spec/examples/simple_worker_spec.rb @@ -1,29 +1,28 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SimpleWorker do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :default, - 'retry' => true, - 'lock' => :until_executed, + "queue" => :default, + "retry" => true, + "lock" => :until_executed, } end end - it_behaves_like 'a performing worker', splat_arguments: false do - let(:args) { ['one', 'type' => 'unique', 'id' => 2] } + it_behaves_like "a performing worker", splat_arguments: false do + let(:args) { ["one", "type" => "unique", "id" => 2] } end - describe 'unique_args' do + describe "unique_args" do subject do - described_class.get_sidekiq_options['unique_args'].call(args) + described_class.get_sidekiq_options["unique_args"].call(args) end - let(:args) { ['unique', 'type' => 'unique', 'id' => 2] } + let(:args) { ["unique", "type" => "unique", "id" => 2] } - it { is_expected.to eq(['unique']) } + it { is_expected.to eq(["unique"]) } end end diff --git a/spec/examples/spawn_simple_worker_spec.rb b/spec/examples/spawn_simple_worker_spec.rb index 2baac3b7b..0e1f09671 100644 --- a/spec/examples/spawn_simple_worker_spec.rb +++ b/spec/examples/spawn_simple_worker_spec.rb @@ -1,27 +1,30 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SpawnSimpleWorker do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :not_default, - 'retry' => true, + "queue" => :not_default, + "retry" => true, } end end - it_behaves_like 'a performing worker', splat_arguments: false do - let(:args) { ['one', 'type' => 'unique', 'id' => 2] } + it_behaves_like "a performing worker", splat_arguments: false do + let(:args) { ["one", "type" => "unique", "id" => 2] } end - describe '#perform' do + describe "#perform" do let(:args) { %w[one two] } - it 'spawns another job' do - expect(SimpleWorker).to receive(:perform_async).with(args).and_return(true) + before do + allow(SimpleWorker).to receive(:perform_async).with(args).and_return(true) + end + + it "spawns another job" do described_class.new.perform(args) + expect(SimpleWorker).to have_received(:perform_async).with(args) end end end diff --git a/spec/examples/test_class_spec.rb b/spec/examples/test_class_spec.rb index 196246334..6e7811333 100644 --- a/spec/examples/test_class_spec.rb +++ b/spec/examples/test_class_spec.rb @@ -1,13 +1,12 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe TestClass do - describe '.run' do + describe ".run" do subject { described_class.run(arg) } - let(:arg) { 'the one' } + let(:arg) { "the one" } - it { is_expected.to eq('the one') } + it { is_expected.to eq("the one") } end end diff --git a/spec/examples/unique_across_workers_job_spec.rb b/spec/examples/unique_across_workers_job_spec.rb index fb877269d..8e9d79992 100644 --- a/spec/examples/unique_across_workers_job_spec.rb +++ b/spec/examples/unique_across_workers_job_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UniqueAcrossWorkersJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'retry' => true, - 'lock' => :until_executed, - 'unique_across_workers' => true, + "retry" => true, + "lock" => :until_executed, + "unique_across_workers" => true, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { %w[one two] } end end diff --git a/spec/examples/unique_job_on_conflict_raise_spec.rb b/spec/examples/unique_job_on_conflict_raise_spec.rb index 5e01ffa81..69c26eda9 100644 --- a/spec/examples/unique_job_on_conflict_raise_spec.rb +++ b/spec/examples/unique_job_on_conflict_raise_spec.rb @@ -1,20 +1,19 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UniqueJobOnConflictRaise do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'lock' => :while_executing, - 'on_conflict' => :raise, - 'queue' => :customqueue, - 'retry' => true, + "lock" => :while_executing, + "on_conflict" => :raise, + "queue" => :customqueue, + "retry" => true, } end end - it_behaves_like 'a performing worker' do - let(:args) { ['hundred', 'type' => 'extremely unique', 'id' => 44] } + it_behaves_like "a performing worker" do + let(:args) { ["hundred", "type" => "extremely unique", "id" => 44] } end end diff --git a/spec/examples/unique_job_on_conflict_reject_spec.rb b/spec/examples/unique_job_on_conflict_reject_spec.rb index 4622410ec..57347cc58 100644 --- a/spec/examples/unique_job_on_conflict_reject_spec.rb +++ b/spec/examples/unique_job_on_conflict_reject_spec.rb @@ -1,20 +1,19 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UniqueJobOnConflictReject do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'lock' => :while_executing, - 'on_conflict' => :reject, - 'queue' => :customqueue, - 'retry' => true, + "lock" => :while_executing, + "on_conflict" => :reject, + "queue" => :customqueue, + "retry" => true, } end end - it_behaves_like 'a performing worker' do - let(:args) { ['hundred', 'type' => 'extremely unique', 'id' => 44] } + it_behaves_like "a performing worker" do + let(:args) { ["hundred", "type" => "extremely unique", "id" => 44] } end end diff --git a/spec/examples/unique_job_on_conflict_reschedule_spec.rb b/spec/examples/unique_job_on_conflict_reschedule_spec.rb index d4840ecee..f8d813bb1 100644 --- a/spec/examples/unique_job_on_conflict_reschedule_spec.rb +++ b/spec/examples/unique_job_on_conflict_reschedule_spec.rb @@ -1,20 +1,19 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UniqueJobOnConflictReschedule do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'lock' => :while_executing, - 'on_conflict' => :reschedule, - 'queue' => :customqueue, - 'retry' => true, + "lock" => :while_executing, + "on_conflict" => :reschedule, + "queue" => :customqueue, + "retry" => true, } end end - it_behaves_like 'a performing worker' do - let(:args) { ['hundred', 'type' => 'extremely unique', 'id' => 44] } + it_behaves_like "a performing worker" do + let(:args) { ["hundred", "type" => "extremely unique", "id" => 44] } end end diff --git a/spec/examples/unique_job_with_nil_unique_args_spec.rb b/spec/examples/unique_job_with_nil_unique_args_spec.rb index 0daa3a0ee..2fd162a59 100644 --- a/spec/examples/unique_job_with_nil_unique_args_spec.rb +++ b/spec/examples/unique_job_with_nil_unique_args_spec.rb @@ -1,28 +1,27 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UniqueJobWithNilUniqueArgs do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'backtrace' => true, - 'queue' => :customqueue, - 'retry' => true, - 'lock' => :until_executed, - 'unique_args' => :unique_args, + "backtrace" => true, + "queue" => :customqueue, + "retry" => true, + "lock" => :until_executed, + "unique_args" => :unique_args, } end end - it_behaves_like 'a performing worker', splat_arguments: false do - let(:args) { ['argument one', 'two', 'three'] } + it_behaves_like "a performing worker", splat_arguments: false do + let(:args) { ["argument one", "two", "three"] } end - describe '.unique_args' do + describe ".unique_args" do subject { described_class.unique_args(args) } - let(:args) { ['argument one', 'two', 'three'] } + let(:args) { ["argument one", "two", "three"] } it { is_expected.to eq(nil) } end diff --git a/spec/examples/unique_job_with_no_unique_args_method_spec.rb b/spec/examples/unique_job_with_no_unique_args_method_spec.rb index 6c7b5d98e..b506130f4 100644 --- a/spec/examples/unique_job_with_no_unique_args_method_spec.rb +++ b/spec/examples/unique_job_with_no_unique_args_method_spec.rb @@ -1,21 +1,20 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UniqueJobWithNoUniqueArgsMethod do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'backtrace' => true, - 'queue' => :customqueue, - 'retry' => true, - 'lock' => :until_executed, - 'unique_args' => :filtered_args, + "backtrace" => true, + "queue" => :customqueue, + "retry" => true, + "lock" => :until_executed, + "unique_args" => :filtered_args, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { %w[one two] } end end diff --git a/spec/examples/unique_job_without_unique_args_parameter_spec.rb b/spec/examples/unique_job_without_unique_args_parameter_spec.rb index bb47faab3..dd4e4a703 100644 --- a/spec/examples/unique_job_without_unique_args_parameter_spec.rb +++ b/spec/examples/unique_job_without_unique_args_parameter_spec.rb @@ -1,21 +1,20 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UniqueJobWithoutUniqueArgsParameter do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'backtrace' => true, - 'queue' => :customqueue, - 'retry' => true, - 'lock' => :until_executed, - 'unique_args' => :unique_args, + "backtrace" => true, + "queue" => :customqueue, + "retry" => true, + "lock" => :until_executed, + "unique_args" => :unique_args, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { true } end end diff --git a/spec/examples/unique_on_all_queues_job_spec.rb b/spec/examples/unique_on_all_queues_job_spec.rb index 513550878..58e93e19e 100644 --- a/spec/examples/unique_on_all_queues_job_spec.rb +++ b/spec/examples/unique_on_all_queues_job_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UniqueOnAllQueuesJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'retry' => true, - 'lock' => :until_executed, - 'unique_on_all_queues' => true, + "retry" => true, + "lock" => :until_executed, + "unique_on_all_queues" => true, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { %w[one two three] } end end diff --git a/spec/examples/until_and_while_executing_job_spec.rb b/spec/examples/until_and_while_executing_job_spec.rb index 13aa01b66..b107d98f9 100644 --- a/spec/examples/until_and_while_executing_job_spec.rb +++ b/spec/examples/until_and_while_executing_job_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UntilAndWhileExecutingJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :working, - 'retry' => true, - 'lock' => :until_and_while_executing, + "queue" => :working, + "retry" => true, + "lock" => :until_and_while_executing, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { [%w[one]] } end end diff --git a/spec/examples/until_executed2_job_spec.rb b/spec/examples/until_executed2_job_spec.rb index 7dae3045f..a3d813e34 100644 --- a/spec/examples/until_executed2_job_spec.rb +++ b/spec/examples/until_executed2_job_spec.rb @@ -1,21 +1,20 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UntilExecuted2Job do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'backtrace' => 10, - 'lock' => :until_executed, - 'lock_timeout' => 0, - 'queue' => :working, - 'retry' => 1, + "backtrace" => 10, + "lock" => :until_executed, + "lock_timeout" => 0, + "queue" => :working, + "retry" => 1, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { %w[one two] } end end diff --git a/spec/examples/until_executed_job_spec.rb b/spec/examples/until_executed_job_spec.rb index ec0ca0a21..05ebe5d46 100644 --- a/spec/examples/until_executed_job_spec.rb +++ b/spec/examples/until_executed_job_spec.rb @@ -1,22 +1,21 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UntilExecutedJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'backtrace' => 10, - 'lock_timeout' => 0, - 'lock_expiration' => 5000, - 'queue' => :working, - 'retry' => 1, - 'lock' => :until_executed, + "backtrace" => 10, + "lock_timeout" => 0, + "lock_expiration" => 5000, + "queue" => :working, + "retry" => 1, + "lock" => :until_executed, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { %w[one two] } end end diff --git a/spec/examples/until_executing_job_spec.rb b/spec/examples/until_executing_job_spec.rb index dd5675b9c..6ad28f657 100644 --- a/spec/examples/until_executing_job_spec.rb +++ b/spec/examples/until_executing_job_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UntilExecutingJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'queue' => :working, - 'retry' => true, - 'lock' => :until_executing, + "queue" => :working, + "retry" => true, + "lock" => :until_executing, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { no_args } end end diff --git a/spec/examples/until_expired_job_spec.rb b/spec/examples/until_expired_job_spec.rb index 90e88d56d..2ff813ba0 100644 --- a/spec/examples/until_expired_job_spec.rb +++ b/spec/examples/until_expired_job_spec.rb @@ -1,20 +1,19 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UntilExpiredJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'lock_expiration' => 1, - 'lock_timeout' => 0, - 'retry' => true, - 'lock' => :until_expired, + "lock_expiration" => 1, + "lock_timeout" => 0, + "retry" => true, + "lock" => :until_expired, } end end - it_behaves_like 'a performing worker' do - let(:args) { 'one' } + it_behaves_like "a performing worker" do + let(:args) { "one" } end end diff --git a/spec/examples/until_global_expired_job_spec.rb b/spec/examples/until_global_expired_job_spec.rb index a2a578602..e9169676c 100644 --- a/spec/examples/until_global_expired_job_spec.rb +++ b/spec/examples/until_global_expired_job_spec.rb @@ -1,18 +1,17 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe UntilGlobalExpiredJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'retry' => true, - 'lock' => :until_expired, + "retry" => true, + "lock" => :until_expired, } end end - it_behaves_like 'a performing worker' do - let(:args) { 'one' } + it_behaves_like "a performing worker" do + let(:args) { "one" } end end diff --git a/spec/examples/while_executing_job_spec.rb b/spec/examples/while_executing_job_spec.rb index 13dcd3981..61a3b5b52 100644 --- a/spec/examples/while_executing_job_spec.rb +++ b/spec/examples/while_executing_job_spec.rb @@ -1,26 +1,25 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe WhileExecutingJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'backtrace' => 10, - 'queue' => :working, - 'retry' => 1, - 'lock' => :while_executing, + "backtrace" => 10, + "queue" => :working, + "retry" => 1, + "lock" => :while_executing, } end end - it_behaves_like 'a performing worker' do - let(:args) { 'one' } + it_behaves_like "a performing worker" do + let(:args) { "one" } end - describe 'client middleware' do - context 'when job is already scheduled' do - it 'pushes the job immediately' do + describe "client middleware" do + context "when job is already scheduled" do + it "pushes the job immediately" do described_class.perform_in(3600, 1) expect(described_class.perform_async(1)).not_to eq(nil) end diff --git a/spec/examples/without_argument_job_spec.rb b/spec/examples/without_argument_job_spec.rb index 0a05d44ec..408e0ce2d 100644 --- a/spec/examples/without_argument_job_spec.rb +++ b/spec/examples/without_argument_job_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe WithoutArgumentJob do - it_behaves_like 'sidekiq with options' do + it_behaves_like "sidekiq with options" do let(:options) do { - 'log_duplicate_payload' => true, - 'retry' => true, - 'lock' => :until_executed, + "log_duplicate_payload" => true, + "retry" => true, + "lock" => :until_executed, } end end - it_behaves_like 'a performing worker' do + it_behaves_like "a performing worker" do let(:args) { no_args } end end diff --git a/spec/integration/sidekiq/retry_set_spec.rb b/spec/integration/sidekiq/retry_set_spec.rb index fa1d27f80..2e2a26c69 100644 --- a/spec/integration/sidekiq/retry_set_spec.rb +++ b/spec/integration/sidekiq/retry_set_spec.rb @@ -1,49 +1,56 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe Sidekiq::RetrySet, redis: :redis do let(:locksmith) { SidekiqUniqueJobs::Locksmith.new(item) } let(:args) { [1, 2] } let(:worker_class) { MyUniqueJob } - let(:jid) { 'ajobid' } + let(:jid) { "ajobid" } let(:lock) { :until_executed } let(:lock_expiration) { 7_200 } let(:queue) { :customqueue } let(:retry_at) { Time.now.to_f + 360 } - let(:unique_digest) { 'uniquejobs:9e9b5ce5d423d3ea470977004b50ff84' } + let(:unique_digest) { "uniquejobs:9e9b5ce5d423d3ea470977004b50ff84" } let(:item) do { - 'args' => args, - 'class' => worker_class, - 'failed_at' => Time.now.to_f, - 'jid' => jid, - 'lock' => lock, - 'lock_expiration' => lock_expiration, - 'queue' => queue, - 'retry_at' => retry_at, - 'retry_count' => 1, - 'unique_digest' => unique_digest, + "args" => args, + "class" => worker_class, + "failed_at" => Time.now.to_f, + "jid" => jid, + "lock" => lock, + "lock_expiration" => lock_expiration, + "queue" => queue, + "retry_at" => retry_at, + "retry_count" => 1, + "unique_digest" => unique_digest, } end before do - zadd('retry', retry_at.to_s, Sidekiq.dump_json(item)) - expect(retry_count).to eq(1) + zadd("retry", retry_at.to_s, Sidekiq.dump_json(item)) end - context 'when a job is locked' do + specify { expect(retry_count).to eq(1) } + + context "when a job is locked" do + let(:locked_jid) { locksmith.lock } + before do - expect(locksmith.lock).to eq(jid) + locked_jid + end + + specify { expect(locked_jid).to eq(jid) } + specify do expect(unique_keys).to match_array(%W[ #{unique_digest}:EXISTS #{unique_digest}:GRABBED ]) - expect(ttl("#{unique_digest}:EXISTS")).to eq(lock_expiration) - expect(ttl("#{unique_digest}:GRABBED")).to eq(-1) end - it 'can be put back on queue' do + specify { expect(ttl("#{unique_digest}:EXISTS")).to eq(lock_expiration) } + specify { expect(ttl("#{unique_digest}:GRABBED")).to eq(-1) } + + it "can be put back on queue" do expect { described_class.new.retry_all } .to change { queue_count(queue) } .from(0).to(1) diff --git a/spec/integration/sidekiq_unique_jobs/client/middleware_spec.rb b/spec/integration/sidekiq_unique_jobs/client/middleware_spec.rb index 03bf18445..2d11b620e 100644 --- a/spec/integration/sidekiq_unique_jobs/client/middleware_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/client/middleware_spec.rb @@ -1,11 +1,10 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Client::Middleware, redis: :redis, redis_db: 1 do - describe 'when a job is already scheduled' do - it 'processes jobs properly' do - jid = NotifyWorker.perform_in(1, 183, 'xxxx') + describe "when a job is already scheduled" do + it "processes jobs properly" do + jid = NotifyWorker.perform_in(1, 183, "xxxx") expect(jid).not_to eq(nil) expect(schedule_count).to eq(1) @@ -17,7 +16,7 @@ expect(keys).to include(*expected) end - it 'rejects nested subsequent jobs with the same arguments' do + it "rejects nested subsequent jobs with the same arguments" do expect(SimpleWorker.perform_async(1)).not_to eq(nil) expect(SimpleWorker.perform_async(1)).to eq(nil) expect(SimpleWorker.perform_in(60, 1)).to eq(nil) @@ -26,11 +25,11 @@ expect(schedule_count).to eq(0) expect(SpawnSimpleWorker.perform_async(1)).not_to eq(nil) - expect(queue_count('default')).to eq(1) - expect(queue_count('not_default')).to eq(1) + expect(queue_count("default")).to eq(1) + expect(queue_count("not_default")).to eq(1) end - it 'schedules new jobs when arguments differ' do + it "schedules new jobs when arguments differ" do [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20].each do |x| MainJob.perform_in(x, x) end @@ -38,7 +37,7 @@ expect(schedule_count).to eq(20) end - it 'schedules allows jobs to be scheduled ' do + it "schedules allows jobs to be scheduled " do class ShitClass def self.do_it(_one) # whatever @@ -53,154 +52,155 @@ def self.do_it(_one) end end - it 'does not push duplicate messages when unique_args are filtered with a proc' do + it "does not push duplicate messages when unique_args are filtered with a proc" do 10.times { MyUniqueJobWithFilterProc.perform_async(1) } - expect(queue_count('customqueue')).to eq(1) + expect(queue_count("customqueue")).to eq(1) Sidekiq.redis(&:flushdb) - expect(queue_count('customqueue')).to eq(0) + expect(queue_count("customqueue")).to eq(0) 10.times do Sidekiq::Client.push( - 'class' => MyUniqueJobWithFilterProc, - 'queue' => 'customqueue', - 'args' => [1, type: 'value', some: 'not used'], + "class" => MyUniqueJobWithFilterProc, + "queue" => "customqueue", + "args" => [1, type: "value", some: "not used"], ) end - expect(queue_count('customqueue')).to eq(1) + expect(queue_count("customqueue")).to eq(1) end - it 'does not push duplicate messages when unique_args are filtered with a method' do + it "does not push duplicate messages when unique_args are filtered with a method" do 10.times { MyUniqueJobWithFilterMethod.perform_async(1) } - expect(queue_count('customqueue')).to eq(1) + expect(queue_count("customqueue")).to eq(1) Sidekiq.redis(&:flushdb) - expect(queue_count('customqueue')).to eq(0) + expect(queue_count("customqueue")).to eq(0) 10.times do Sidekiq::Client.push( - 'class' => MyUniqueJobWithFilterMethod, - 'queue' => 'customqueue', - 'args' => [1, type: 'value', some: 'not used'], + "class" => MyUniqueJobWithFilterMethod, + "queue" => "customqueue", + "args" => [1, type: "value", some: "not used"], ) end - expect(queue_count('customqueue')).to eq(1) + expect(queue_count("customqueue")).to eq(1) end - it 'does not queue duplicates when when calling delay' do - 10.times { PlainClass.delay(unique: :until_executed, queue: 'customqueue').run(1) } + it "does not queue duplicates when when calling delay" do + 10.times { PlainClass.delay(unique: :until_executed, queue: "customqueue").run(1) } - expect(queue_count('customqueue')).to eq(1) + expect(queue_count("customqueue")).to eq(1) end - context 'when class is not unique' do - it 'pushes duplicate messages' do + context "when class is not unique" do + it "pushes duplicate messages" do 10.times do - Sidekiq::Client.push('class' => CustomQueueJob, 'queue' => 'customqueue', 'args' => [1, 2]) + Sidekiq::Client.push("class" => CustomQueueJob, "queue" => "customqueue", "args" => [1, 2]) end - expect(queue_count('customqueue')).to eq(10) + expect(queue_count("customqueue")).to eq(10) end end - describe 'when unique_args is defined' do - context 'when filter method is defined' do - it 'pushes no duplicate messages' do + describe "when unique_args is defined" do + context "when filter method is defined" do + it "pushes no duplicate messages" do expect(CustomQueueJobWithFilterMethod).to respond_to(:args_filter) - expect(CustomQueueJobWithFilterMethod.get_sidekiq_options['unique_args']).to eq :args_filter + expect(CustomQueueJobWithFilterMethod.get_sidekiq_options["unique_args"]).to eq :args_filter (0..10).each do |i| Sidekiq::Client.push( - 'class' => CustomQueueJobWithFilterMethod, - 'queue' => 'customqueue', - 'args' => [1, i], + "class" => CustomQueueJobWithFilterMethod, + "queue" => "customqueue", + "args" => [1, i], ) end - expect(queue_count('customqueue')).to eq(1) + expect(queue_count("customqueue")).to eq(1) end end - context 'when filter proc is defined' do - let(:args) { [1, { random: rand, name: 'foobar' }] } + context "when filter proc is defined" do + let(:args) { [1, { random: rand, name: "foobar" }] } - it 'pushes no duplicate messages' do + it "pushes no duplicate messages" do 100.times { CustomQueueJobWithFilterProc.perform_async(args) } - expect(queue_count('customqueue')).to eq(1) + expect(queue_count("customqueue")).to eq(1) end end - context 'when unique_on_all_queues is set' do - it 'pushes no duplicate messages on other queues' do - item = { 'class' => UniqueOnAllQueuesJob, 'args' => [1, 2] } - Sidekiq::Client.push(item.merge('queue' => 'customqueue')) - Sidekiq::Client.push(item.merge('queue' => 'customqueue2')) + context "when unique_on_all_queues is set" do + it "pushes no duplicate messages on other queues" do + item = { "class" => UniqueOnAllQueuesJob, "args" => [1, 2] } + Sidekiq::Client.push(item.merge("queue" => "customqueue")) + Sidekiq::Client.push(item.merge("queue" => "customqueue2")) - expect(queue_count('customqueue')).to eq(1) - expect(queue_count('customqueue2')).to eq(0) + expect(queue_count("customqueue")).to eq(1) + expect(queue_count("customqueue2")).to eq(0) end end - context 'when unique_across_workers is set' do - it 'does not push duplicate messages for other workers' do + context "when unique_across_workers is set" do + it "does not push duplicate messages for other workers" do item_one = { - 'queue' => 'customqueue1', - 'class' => UniqueAcrossWorkersJob, - 'unique_across_workers' => true, - 'args' => [1, 2], + "queue" => "customqueue1", + "class" => UniqueAcrossWorkersJob, + "unique_across_workers" => true, + "args" => [1, 2], } item_two = { - 'queue' => 'customqueue1', - 'class' => MyUniqueJob, - 'unique_across_workers' => true, - 'args' => [1, 2], + "queue" => "customqueue1", + "class" => MyUniqueJob, + "unique_across_workers" => true, + "args" => [1, 2], } Sidekiq::Client.push(item_one) Sidekiq::Client.push(item_two) - expect(queue_count('customqueue1')).to eq(1) + expect(queue_count("customqueue1")).to eq(1) end end end - it 'expires the digest when a scheduled job is scheduled at' do + it "expires the digest when a scheduled job is scheduled at" do expected_expires_at = Time.now.to_i + 15 * 60 - Time.now.utc.to_i - MyUniqueJob.perform_in(expected_expires_at, 'mika', 'hel') + MyUniqueJob.perform_in(expected_expires_at, "mika", "hel") unique_keys.each do |key| - next if key.end_with?(':GRABBED') + next if key.end_with?(":GRABBED") expect(ttl(key)).to be_within(10).of(8_099) end end - it 'logs duplicate payload when config turned on' do - expect(Sidekiq.logger).to receive(:warn).with(/^payload is not unique/) + it "logs duplicate payload when config turned on" do + allow(Sidekiq.logger).to receive(:warn) with_sidekiq_options_for(UntilExecutedJob, log_duplicate_payload: true) do 2.times do - Sidekiq::Client.push('class' => UntilExecutedJob, 'queue' => 'customqueue', 'args' => [1, 2]) + Sidekiq::Client.push("class" => UntilExecutedJob, "queue" => "customqueue", "args" => [1, 2]) end - expect(queue_count('customqueue')).to eq(1) + expect(queue_count("customqueue")).to eq(1) end + expect(Sidekiq.logger).to have_received(:warn).with(/^payload is not unique/) end - it 'does not log duplicate payload when config turned off' do - expect(SidekiqUniqueJobs.logger).not_to receive(:warn).with(/^payload is not unique/) - + it "does not log duplicate payload when config turned off" do + allow(SidekiqUniqueJobs.logger).to receive(:warn) with_sidekiq_options_for(UntilExecutedJob, log_duplicate_payload: false) do 2.times do - Sidekiq::Client.push('class' => UntilExecutedJob, 'queue' => 'customqueue', 'args' => [1, 2]) + Sidekiq::Client.push("class" => UntilExecutedJob, "queue" => "customqueue", "args" => [1, 2]) end - expect(queue_count('customqueue')).to eq(1) + expect(queue_count("customqueue")).to eq(1) end + expect(SidekiqUniqueJobs.logger).not_to have_received(:warn).with(/^payload is not unique/) end end diff --git a/spec/integration/sidekiq_unique_jobs/legacy_lock_spec.rb b/spec/integration/sidekiq_unique_jobs/legacy_lock_spec.rb index 92b5eb81b..7d5986a1f 100644 --- a/spec/integration/sidekiq_unique_jobs/legacy_lock_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/legacy_lock_spec.rb @@ -1,122 +1,119 @@ # frozen_string_literal: true -require 'spec_helper' - # rubocop:disable RSpec/FilePath RSpec.describe SidekiqUniqueJobs::Locksmith, redis: :redis do - let(:locksmith_one) { described_class.new(lock_item) } + let(:locksmith_one) { described_class.new(lock_item) } let(:lock_expiration) { nil } let(:redis_pool) { nil } - let(:jid_one) { 'maaaahjid' } - let(:jid_two) { 'anotherjid' } - let(:unique_digest) { 'uniquejobs:test_mutex_key' } - let(:queue) { 'dupsallowed' } + let(:jid_one) { "maaaahjid" } + let(:jid_two) { "anotherjid" } + let(:unique_digest) { "uniquejobs:test_mutex_key" } + let(:queue) { "dupsallowed" } let(:unique) { :until_executed } let(:worker_class) { UntilExecutedJob } let(:lock_item) do { - 'args' => [1], - 'class' => UntilExecutedJob, - 'jid' => jid_one, - 'lock_expiration' => lock_expiration, - 'queue' => queue, - 'lock' => unique, - 'unique_digest' => unique_digest, + "args" => [1], + "class" => UntilExecutedJob, + "jid" => jid_one, + "lock_expiration" => lock_expiration, + "queue" => queue, + "lock" => unique, + "unique_digest" => unique_digest, } end let(:locksmith_two) { described_class.new(lock_item_two) } - let(:lock_item_two) { lock_item.merge('jid' => jid_two) } + let(:lock_item_two) { lock_item.merge("jid" => jid_two) } - context 'with a legacy uniquejobs hash' do + context "with a legacy uniquejobs hash" do before do SidekiqUniqueJobs.redis do |conn| conn.multi do - conn.hset('uniquejobs', 'bogus', 'value') - conn.hset('uniquejobs', 'bogus', 'value 2') + conn.hset("uniquejobs", "bogus", "value") + conn.hset("uniquejobs", "bogus", "value 2") end end end - it 'deletes the uniquejobs hash' do - expect(keys).to include('uniquejobs') - expect(hexists('uniquejobs', 'bogus')).to eq(true) + it "deletes the uniquejobs hash" do + expect(keys).to include("uniquejobs") + expect(hexists("uniquejobs", "bogus")).to eq(true) locksmith_one.delete - expect(keys).not_to include('uniquejobs') - expect(hexists('uniquejobs', 'bogus')).to eq(false) + expect(keys).not_to include("uniquejobs") + expect(hexists("uniquejobs", "bogus")).to eq(false) end end - context 'with a legacy lock' do - before do - result = SidekiqUniqueJobs::Scripts.call( + context "with a legacy lock" do + let(:lock_value) { jid_one } + + let!(:old_lock) do + SidekiqUniqueJobs::Scripts.call( :acquire_lock, redis_pool, keys: [unique_digest], argv: [lock_value, lock_expiration], ) - - expect(result).to eq(1) - expect(unique_keys).to include(unique_digest) end - context 'when lock_expiration is unset' do - let(:lock_value) { jid_one } + specify { expect(old_lock).to eq(1) } + specify { expect(unique_keys).to include(unique_digest) } - it 'unlocks immediately' do + context "when lock_expiration is unset" do + it "unlocks immediately" do locksmith_one.unlock!(jid_one) expect(ttl(unique_digest)).to eq(-2) # key does not exist anymore end - it 'can soft deletes the lock' do + it "can soft deletes the lock" do expect(locksmith_one.delete).to eq(nil) expect(unique_keys).not_to include(unique_digest) end - it 'can force delete the lock' do + it "can force delete the lock" do expect(locksmith_one.delete!).to eq(nil) expect(unique_keys).not_to include(unique_digest) end end - context 'when lock_expiration is set' do - let(:lock_value) { jid_one } + context "when lock_expiration is set" do let(:lock_expiration) { 10 } - it 'can signal to expire the lock after 10' do + it "can signal to expire the lock after 10" do locksmith_one.unlock(jid_one) expect(ttl(unique_digest)).to be_within(1).of(10) end - it 'cannot soft delete the lock' do + it "cannot soft delete the lock" do expect(locksmith_one.delete).to eq(nil) expect(unique_keys).to include(unique_digest) end - it 'can force delete the lock' do + it "can force delete the lock" do expect(locksmith_one.delete!).to eq(nil) expect(unique_keys).not_to include(unique_digest) end end - context 'when the value of unique_digest is 2' do - let(:lock_value) { '2' } + context "when the value of unique_digest is 2" do + let(:lock_value) { "2" } - it 'returns the stored jid' do + it "returns the stored jid" do expect(locksmith_one.lock(0)).to eq(jid_one) end end - context 'when the value of unique_digest is jid' do + context "when the value of unique_digest is jid" do let(:lock_value) { jid_one } - it 'returns the stored jid' do + it "returns the stored jid" do expect(locksmith_one.lock(0)).to eq(jid_one) end - it 'can not be locked by another jid' do + it "can not be locked by another jid" do expect(locksmith_two.lock(0)).to eq(nil) end end diff --git a/spec/integration/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb b/spec/integration/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb index 422b4f224..31e5d9530 100644 --- a/spec/integration/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::UntilAndWhileExecuting, redis: :redis, redis_db: 3 do include SidekiqHelpers @@ -11,8 +10,8 @@ let(:process_two) { described_class.new(item_two, callback) } let(:runtime_two) { SidekiqUniqueJobs::Lock::WhileExecuting.new(item_two.dup, callback) } - let(:jid_one) { 'jid one' } - let(:jid_two) { 'jid two' } + let(:jid_one) { "jid one" } + let(:jid_two) { "jid two" } let(:lock_timeout) { nil } let(:sleepy_time) { 0 } let(:worker_class) { UntilAndWhileExecutingJob } @@ -21,15 +20,15 @@ let(:args) { [sleepy_time] } let(:callback) { -> {} } let(:item_one) do - { 'jid' => jid_one, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args, - 'lock_timeout' => lock_timeout } + { "jid" => jid_one, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args, + "lock_timeout" => lock_timeout } end let(:item_two) do - item_one.merge('jid' => jid_two) + item_one.merge("jid" => jid_two) end before do @@ -37,33 +36,33 @@ allow(process_two).to receive(:runtime_lock).and_return(runtime_two) end - it_behaves_like 'a lock implementation' + it_behaves_like "a lock implementation" - it 'has not locked runtime_one' do + it "has not locked runtime_one" do process_one.lock expect(runtime_one).not_to be_locked end - context 'when process_one executes the job' do - it 'releases the lock for process_one' do + context "when process_one executes the job" do + it "releases the lock for process_one" do process_one.execute do expect(process_one).not_to be_locked end end - it 'is locked by runtime_one' do + it "is locked by runtime_one" do process_one.execute do expect(runtime_one).to be_locked end end - it 'allows process_two to lock' do + it "allows process_two to lock" do process_one.execute do expect(process_two.lock).to eq(jid_two) end end - it 'process two cannot execute the job' do + it "process two cannot execute the job" do process_one.execute do process_two.lock unset = true diff --git a/spec/integration/sidekiq_unique_jobs/lock/until_executed_spec.rb b/spec/integration/sidekiq_unique_jobs/lock/until_executed_spec.rb index fe0df7f6b..13d53fb88 100644 --- a/spec/integration/sidekiq_unique_jobs/lock/until_executed_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/lock/until_executed_spec.rb @@ -1,59 +1,58 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::UntilExecuted, redis: :redis do include SidekiqHelpers let(:process_one) { described_class.new(item_one, callback) } let(:process_two) { described_class.new(item_two, callback) } - let(:jid_one) { 'jid one' } - let(:jid_two) { 'jid two' } + let(:jid_one) { "jid one" } + let(:jid_two) { "jid two" } let(:worker_class) { UntilExecutedJob } let(:unique) { :until_executed } let(:queue) { :executed } let(:args) { %w[array of arguments] } let(:callback) { -> {} } let(:item_one) do - { 'jid' => jid_one, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args } + { "jid" => jid_one, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args } end let(:item_two) do - { 'jid' => jid_two, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args } + { "jid" => jid_two, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args } end before do allow(callback).to receive(:call).and_call_original end - describe '#lock' do - it_behaves_like 'a lock implementation' + describe "#lock" do + it_behaves_like "a lock implementation" end - describe '#execute' do - it_behaves_like 'an executing lock implementation' + describe "#execute" do + it_behaves_like "an executing lock implementation" - it 'unlocks after executing' do + it "unlocks after executing" do process_one.lock process_one.execute {} expect(process_one).not_to be_locked end end - describe '#delete' do + describe "#delete" do subject(:delete) { process_one.delete } - context 'when locked' do - context 'when expiration is not negative' do - it 'deletes the lock without fuss' do + context "when locked" do + context "when expiration is not negative" do + it "deletes the lock without fuss" do worker_class.use_options(lock_expiration: nil) do process_one.lock expect { delete }.to change { unique_keys.size }.from(2).to(0) @@ -61,24 +60,24 @@ end end - context 'when expiration is positive' do - it 'does not delete the lock' do + context "when expiration is positive" do + it "does not delete the lock" do worker_class.use_options(lock_expiration: 100) do process_one.lock - expect { delete }.not_to change(unique_keys, :size) + expect { delete }.not_to change { unique_keys.size } end end end end end - describe '#delete!' do + describe "#delete!" do subject(:delete!) { process_one.delete! } - context 'when locked' do + context "when locked" do before { process_one.lock } - it 'deletes the lock without fuss' do + it "deletes the lock without fuss" do expect { delete! }.to change { unique_keys.size }.from(2).to(0) end end diff --git a/spec/integration/sidekiq_unique_jobs/lock/until_executing_spec.rb b/spec/integration/sidekiq_unique_jobs/lock/until_executing_spec.rb index b7cc81d6c..65eb41001 100644 --- a/spec/integration/sidekiq_unique_jobs/lock/until_executing_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/lock/until_executing_spec.rb @@ -1,45 +1,44 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::UntilExecuting, redis: :redis do include SidekiqHelpers let(:process_one) { described_class.new(item_one, callback) } let(:process_two) { described_class.new(item_two, callback) } - let(:jid_one) { 'jid one' } - let(:jid_two) { 'jid two' } + let(:jid_one) { "jid one" } + let(:jid_two) { "jid two" } let(:worker_class) { UntilExecutedJob } let(:unique) { :until_executed } let(:queue) { :executed } let(:args) { %w[array of arguments] } let(:callback) { -> {} } let(:item_one) do - { 'jid' => jid_one, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args } + { "jid" => jid_one, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args } end let(:item_two) do - { 'jid' => jid_two, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args } + { "jid" => jid_two, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args } end before do allow(callback).to receive(:call).and_call_original end - describe '#lock' do - it_behaves_like 'a lock implementation' + describe "#lock" do + it_behaves_like "a lock implementation" end - describe '#execute' do - it 'unlocks before executing' do + describe "#execute" do + it "unlocks before executing" do process_one.lock process_one.execute do expect(process_one).not_to be_locked @@ -47,12 +46,12 @@ end end - describe '#delete' do + describe "#delete" do subject(:delete) { process_one.delete } - context 'when locked' do - context 'when expiration is not negative' do - it 'deletes the lock without fuss' do + context "when locked" do + context "when expiration is not negative" do + it "deletes the lock without fuss" do worker_class.use_options(lock_expiration: nil) do process_one.lock expect { delete }.to change { unique_keys.size }.from(2).to(0) @@ -60,24 +59,24 @@ end end - context 'when expiration is positive' do - it 'does not delete the lock' do + context "when expiration is positive" do + it "does not delete the lock" do worker_class.use_options(lock_expiration: 100) do process_one.lock - expect { delete }.not_to change(unique_keys, :size) + expect { delete }.not_to change { unique_keys.size } end end end end end - describe '#delete!' do + describe "#delete!" do subject(:delete!) { process_one.delete! } - context 'when locked' do + context "when locked" do before { process_one.lock } - it 'deletes the lock without fuss' do + it "deletes the lock without fuss" do expect { delete! }.to change { unique_keys.size }.from(2).to(0) end end diff --git a/spec/integration/sidekiq_unique_jobs/lock/until_expired_spec.rb b/spec/integration/sidekiq_unique_jobs/lock/until_expired_spec.rb index a81f4f014..5aefc863e 100644 --- a/spec/integration/sidekiq_unique_jobs/lock/until_expired_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/lock/until_expired_spec.rb @@ -1,59 +1,58 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::UntilExpired, redis: :redis do include SidekiqHelpers let(:process_one) { described_class.new(item_one, callback) } let(:process_two) { described_class.new(item_two, callback) } - let(:jid_one) { 'jid one' } - let(:jid_two) { 'jid two' } + let(:jid_one) { "jid one" } + let(:jid_two) { "jid two" } let(:worker_class) { UntilExpiredJob } let(:unique) { :until_expired } let(:queue) { :rejecting } let(:args) { %w[array of arguments] } let(:callback) { -> {} } let(:item_one) do - { 'jid' => jid_one, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args } + { "jid" => jid_one, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args } end let(:item_two) do - { 'jid' => jid_two, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args } + { "jid" => jid_two, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args } end before do allow(callback).to receive(:call).and_call_original end - describe '#lock' do - it_behaves_like 'a lock implementation' + describe "#lock" do + it_behaves_like "a lock implementation" end - describe '#execute' do - it_behaves_like 'an executing lock implementation' + describe "#execute" do + it_behaves_like "an executing lock implementation" - it 'keeps lock after executing' do + it "keeps lock after executing" do process_one.lock process_one.execute {} expect(process_one).to be_locked - expect(ttl('uniquejobs:da6005926a8457526e998f0033901dfc:EXISTS')).to eq(1) + expect(ttl("uniquejobs:da6005926a8457526e998f0033901dfc:EXISTS")).to eq(1) end end - describe '#unlock' do - context 'when lock is locked' do + describe "#unlock" do + context "when lock is locked" do before { process_one.lock } - it 'keeps the lock even when unlocking' do + it "keeps the lock even when unlocking" do expect(process_one.unlock).to eq(true) expect(process_one).to be_locked end diff --git a/spec/integration/sidekiq_unique_jobs/lock/while_executing_reject_spec.rb b/spec/integration/sidekiq_unique_jobs/lock/while_executing_reject_spec.rb index 265e41820..609268eb8 100644 --- a/spec/integration/sidekiq_unique_jobs/lock/while_executing_reject_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/lock/while_executing_reject_spec.rb @@ -1,37 +1,36 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::WhileExecutingReject, redis: :redis do include SidekiqHelpers let(:process_one) { described_class.new(item_one, callback) } let(:process_two) { described_class.new(item_two, callback) } - let(:jid_one) { 'jid one' } - let(:jid_two) { 'jid two' } + let(:jid_one) { "jid one" } + let(:jid_two) { "jid two" } let(:worker_class) { WhileExecutingRejectJob } let(:unique) { :while_executing_reject } let(:queue) { :rejecting } let(:args) { %w[array of arguments] } let(:callback) { -> {} } let(:item_one) do - { 'jid' => jid_one, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args } + { "jid" => jid_one, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args } end let(:item_two) do - { 'jid' => jid_two, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args } + { "jid" => jid_two, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args } end - describe '#execute' do - it 'does not lock jobs' do + describe "#execute" do + it "does not lock jobs" do expect(process_one.lock).to eq(true) expect(process_one).not_to be_locked @@ -39,15 +38,15 @@ expect(process_two).not_to be_locked end - context 'when job is executing' do - it 'locks the process' do + context "when job is executing" do + it "locks the process" do process_one.execute do expect(process_one).to be_locked end end - shared_examples 'rejects job to deadset' do - it 'moves subsequent jobs to dead queue' do + shared_examples "rejects job to deadset" do + it "moves subsequent jobs to dead queue" do process_one.execute do expect(dead_count).to eq(0) expect { process_two.execute {} } @@ -55,13 +54,13 @@ end end end - it_behaves_like 'rejects job to deadset' + it_behaves_like "rejects job to deadset" - context 'when Sidekiq::DeadSet respond to kill' do - it_behaves_like 'rejects job to deadset' + context "when Sidekiq::DeadSet respond to kill" do + it_behaves_like "rejects job to deadset" end - context 'when Sidekiq::DeadSet does not respond to kill' do + context "when Sidekiq::DeadSet does not respond to kill" do let(:strategy) { SidekiqUniqueJobs::OnConflict::Reject.new(item_two) } before do @@ -69,7 +68,7 @@ allow(process_two).to receive(:strategy).and_return(strategy) end - it_behaves_like 'rejects job to deadset' + it_behaves_like "rejects job to deadset" end end end diff --git a/spec/integration/sidekiq_unique_jobs/lock/while_executing_spec.rb b/spec/integration/sidekiq_unique_jobs/lock/while_executing_spec.rb index 9fc6ea278..bff6aa301 100644 --- a/spec/integration/sidekiq_unique_jobs/lock/while_executing_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/lock/while_executing_spec.rb @@ -1,41 +1,40 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::WhileExecuting, redis: :redis do include SidekiqHelpers let(:process_one) { described_class.new(item_one, callback) } let(:process_two) { described_class.new(item_two, callback) } - let(:jid_one) { 'jid one' } - let(:jid_two) { 'jid two' } + let(:jid_one) { "jid one" } + let(:jid_two) { "jid two" } let(:worker_class) { WhileExecutingJob } let(:unique) { :while_executing } let(:queue) { :while_executing } let(:args) { %w[array of arguments] } let(:callback) { -> {} } let(:item_one) do - { 'jid' => jid_one, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args } + { "jid" => jid_one, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args } end let(:item_two) do - { 'jid' => jid_two, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args } + { "jid" => jid_two, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args } end before do allow(callback).to receive(:call).and_call_original end - describe '#lock' do - it 'does not lock jobs' do + describe "#lock" do + it "does not lock jobs" do expect(process_one.lock).to eq(true) expect(process_one).not_to be_locked @@ -44,20 +43,20 @@ end end - describe '#execute' do - context 'when executing' do - it 'locks the process' do + describe "#execute" do + context "when executing" do + it "locks the process" do process_one.execute do expect(process_one).to be_locked end end - it 'calls back' do + it "calls back" do process_one.execute {} expect(callback).to have_received(:call) end - it 'prevents other processes from executing' do + it "prevents other processes from executing" do process_one.execute do unset = true process_two.execute { unset = false } diff --git a/spec/integration/sidekiq_unique_jobs/locksmith_spec.rb b/spec/integration/sidekiq_unique_jobs/locksmith_spec.rb index 1cc153d35..f65320e72 100644 --- a/spec/integration/sidekiq_unique_jobs/locksmith_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/locksmith_spec.rb @@ -1,48 +1,47 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Locksmith, redis: :redis do let(:locksmith_one) { described_class.new(item_one) } let(:locksmith_two) { described_class.new(item_two) } - let(:jid_one) { 'maaaahjid' } - let(:jid_two) { 'jidmayhem' } - let(:lock_expiration) { nil } - let(:unique_digest) { 'uniquejobs:randomvalue' } + let(:jid_one) { "maaaahjid" } + let(:jid_two) { "jidmayhem" } + let(:lock_expiration) { nil } + let(:unique_digest) { "uniquejobs:randomvalue" } let(:item_one) do { - 'jid' => jid_one, - 'unique_digest' => unique_digest, - 'lock_expiration' => lock_expiration, + "jid" => jid_one, + "unique_digest" => unique_digest, + "lock_expiration" => lock_expiration, } end - let(:item_two) { item_one.merge('jid' => jid_two) } + let(:item_two) { item_one.merge("jid" => jid_two) } - shared_examples_for 'a lock' do - it 'does not exist from the start' do + shared_examples_for "a lock" do + it "does not exist from the start" do expect(locksmith_one.exists?).to eq(false) locksmith_one.lock expect(locksmith_one.exists?).to eq(true) end - it 'is unlocked from the start' do + it "is unlocked from the start" do expect(locksmith_one.locked?).to eq(false) end - it 'locks and unlocks' do + it "locks and unlocks" do locksmith_one.lock(1) expect(locksmith_one.locked?).to eq(true) locksmith_one.unlock expect(locksmith_one.locked?).to eq(false) end - it 'does not lock twice as a mutex' do + it "does not lock twice as a mutex" do expect(locksmith_one.lock(0)).to be_truthy expect(locksmith_two.lock(0)).to eq(nil) end - it 'executes the given code block' do + it "executes the given code block" do code_executed = false locksmith_one.lock(1) do code_executed = true @@ -50,32 +49,32 @@ expect(code_executed).to eq(true) end - it 'passes an exception right through' do + it "passes an exception right through" do expect do locksmith_one.lock(1) do - raise Exception, 'redis lock exception' + raise Exception, "redis lock exception" end - end.to raise_error(Exception, 'redis lock exception') + end.to raise_error(Exception, "redis lock exception") end - it 'does not leave the lock locked after raising an exception' do + it "does not leave the lock locked after raising an exception" do expect do locksmith_one.lock(1) do - raise Exception, 'redis lock exception' + raise Exception, "redis lock exception" end - end.to raise_error(Exception, 'redis lock exception') + end.to raise_error(Exception, "redis lock exception") expect(locksmith_one.locked?).to eq(false) end - it 'returns the value of the block if block-style locking is used' do + it "returns the value of the block if block-style locking is used" do block_value = locksmith_one.lock(1) do 42 end expect(block_value).to eq(42) end - it 'disappears without a trace when calling `delete!`' do + it "disappears without a trace when calling `delete!`" do original_key_size = keys.size locksmith_one.lock @@ -84,7 +83,7 @@ expect(keys.size).to eq(original_key_size) end - it 'does not block when the timeout is zero' do + it "does not block when the timeout is zero" do did_we_get_in = false locksmith_one.lock do @@ -96,48 +95,48 @@ expect(did_we_get_in).to be false end - it 'is locked when the timeout is zero' do + it "is locked when the timeout is zero" do locksmith_one.lock(0) do expect(locksmith_one.locked?).to be true end expect(locksmith_one.locked?).to eq false end - it 'does something' do + it "does something" do expect(locksmith_one.available_count).to eq(1) locksmith_one.lock(0) expect(locksmith_one.available_count).to eq(0) end end - describe 'lock with expiration' do + describe "lock with expiration" do let(:lock_expiration) { 3 } - it_behaves_like 'a lock' + it_behaves_like "a lock" - it 'creates the expected keys' do + it "creates the expected keys" do locksmith_one.lock - expect(ttl('uniquejobs:randomvalue:EXISTS')).to eq(3) + expect(ttl("uniquejobs:randomvalue:EXISTS")).to eq(3) # PLEASE keep this spec. It verifies that the next lock # doesn't persist the exist_key of another lock sleep 1 - expect(ttl('uniquejobs:randomvalue:EXISTS')).to eq(2) + expect(ttl("uniquejobs:randomvalue:EXISTS")).to eq(2) expect(locksmith_two.lock(0)).to eq(nil) - expect(ttl('uniquejobs:randomvalue:EXISTS')).to eq(2) + expect(ttl("uniquejobs:randomvalue:EXISTS")).to eq(2) - expect(unique_digests).to match_array(['uniquejobs:randomvalue']) + expect(unique_digests).to match_array(["uniquejobs:randomvalue"]) expect(unique_keys).to match_array(%w[ uniquejobs:randomvalue:EXISTS uniquejobs:randomvalue:GRABBED ]) end - it 'expires the expected keys' do + it "expires the expected keys" do locksmith_one.lock - expect(unique_digests).to match_array(['uniquejobs:randomvalue']) + expect(unique_digests).to match_array(["uniquejobs:randomvalue"]) expect(unique_keys).to match_array(%w[ uniquejobs:randomvalue:EXISTS uniquejobs:randomvalue:GRABBED @@ -145,12 +144,12 @@ locksmith_one.unlock expect(unique_digests).to match_array([]) - expect(ttl('uniquejobs:randomvalue:EXISTS')).to eq(3) + expect(ttl("uniquejobs:randomvalue:EXISTS")).to eq(3) end - it 'deletes the expected keys' do + it "deletes the expected keys" do locksmith_one.lock - expect(unique_digests).to match_array(['uniquejobs:randomvalue']) + expect(unique_digests).to match_array(["uniquejobs:randomvalue"]) expect(unique_keys).to match_array(%w[ uniquejobs:randomvalue:EXISTS uniquejobs:randomvalue:GRABBED @@ -160,14 +159,14 @@ expect(unique_keys).to match_array(%w[]) end - it 'expires keys' do + it "expires keys" do Sidekiq.redis(&:flushdb) locksmith_one.lock keys = unique_keys expect(unique_keys).not_to include(keys) end - it 'expires keys after unlocking' do + it "expires keys after unlocking" do Sidekiq.redis(&:flushdb) locksmith_one.lock do # noop @@ -226,14 +225,14 @@ # end # end - describe 'current_time' do + describe "current_time" do let(:lock_stale_client_timeout) { 5 } before do Timecop.freeze(Time.local(1990)) end - it 'with time support should return a different time than frozen time' do + it "with time support should return a different time than frozen time" do expect(locksmith_one.send(:current_time)).not_to eq(Time.now) end end diff --git a/spec/integration/sidekiq_unique_jobs/server/middleware/until_and_while_executing_spec.rb b/spec/integration/sidekiq_unique_jobs/server/middleware/until_and_while_executing_spec.rb index 6ff041864..312cb7cab 100644 --- a/spec/integration/sidekiq_unique_jobs/server/middleware/until_and_while_executing_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/server/middleware/until_and_while_executing_spec.rb @@ -1,13 +1,11 @@ # frozen_string_literal: true -require 'spec_helper' - # rubocop:disable RSpec/FilePath, RSpec/DescribeMethod -RSpec.describe SidekiqUniqueJobs::Server::Middleware, 'unique: :until_and_while_executing', redis: :redis do +RSpec.describe SidekiqUniqueJobs::Server::Middleware, "unique: :until_and_while_executing", redis: :redis do let(:server) { described_class.new } - let(:jid_one) { 'jid one' } - let(:jid_two) { 'jid two' } + let(:jid_one) { "jid one" } + let(:jid_two) { "jid two" } let(:lock_timeout) { nil } let(:sleepy_time) { 0 } let(:worker_class) { UntilAndWhileExecutingJob } @@ -16,43 +14,47 @@ let(:args) { [sleepy_time] } let(:callback) { -> {} } let(:item_one) do - { 'jid' => jid_one, - 'class' => worker_class.to_s, - 'queue' => queue, - 'lock' => unique, - 'args' => args, - 'lock_timeout' => lock_timeout } + { "jid" => jid_one, + "class" => worker_class.to_s, + "queue" => queue, + "lock" => unique, + "args" => args, + "lock_timeout" => lock_timeout } end let(:item_two) do - item_one.merge('jid' => jid_two) + item_one.merge("jid" => jid_two) end - let(:available_key) { 'uniquejobs:f07093737839f88af8593c945143574d:AVAILABLE' } - let(:exists_key) { 'uniquejobs:f07093737839f88af8593c945143574d:EXISTS' } - let(:grabbed_key) { 'uniquejobs:f07093737839f88af8593c945143574d:GRABBED' } - let(:version_key) { 'uniquejobs:f07093737839f88af8593c945143574d:VERSION' } + let(:available_key) { "uniquejobs:f07093737839f88af8593c945143574d:AVAILABLE" } + let(:exists_key) { "uniquejobs:f07093737839f88af8593c945143574d:EXISTS" } + let(:grabbed_key) { "uniquejobs:f07093737839f88af8593c945143574d:GRABBED" } + let(:version_key) { "uniquejobs:f07093737839f88af8593c945143574d:VERSION" } + + let(:available_run_key) { "uniquejobs:f07093737839f88af8593c945143574d:RUN:AVAILABLE" } + let(:exists_run_key) { "uniquejobs:f07093737839f88af8593c945143574d:RUN:EXISTS" } + let(:grabbed_run_key) { "uniquejobs:f07093737839f88af8593c945143574d:RUN:GRABBED" } + let(:version_run_key) { "uniquejobs:f07093737839f88af8593c945143574d:RUN:VERSION" } - let(:available_run_key) { 'uniquejobs:f07093737839f88af8593c945143574d:RUN:AVAILABLE' } - let(:exists_run_key) { 'uniquejobs:f07093737839f88af8593c945143574d:RUN:EXISTS' } - let(:grabbed_run_key) { 'uniquejobs:f07093737839f88af8593c945143574d:RUN:GRABBED' } - let(:version_run_key) { 'uniquejobs:f07093737839f88af8593c945143574d:RUN:VERSION' } + context "when item_one is locked" do + let(:pushed_jid) { push_item(item_one) } - context 'when item_one is locked' do before do - expect(push_item(item_one)).to eq(jid_one) + pushed_jid end - context 'with a lock_timeout of 0' do + specify { expect(pushed_jid).to eq(jid_one) } + + context "with a lock_timeout of 0" do let(:lock_timeout) { 0 } - context 'when processing takes 0 seconds' do + context "when processing takes 0 seconds" do let(:sleepy_time) { 0 } - it 'cannot lock item_two' do + it "cannot lock item_two" do expect(push_item(item_two)).to eq(nil) end - it 'item_one can be executed by server' do + it "item_one can be executed by server" do expect(unique_keys).to match_array([grabbed_key, exists_key]) server.call(worker_class, item_one, queue) {} expect(unique_keys).to match_array([available_key, available_run_key]) diff --git a/spec/integration/sidekiq_unique_jobs/server/middleware_spec.rb b/spec/integration/sidekiq_unique_jobs/server/middleware_spec.rb index 3dfc61e37..e26c215b5 100644 --- a/spec/integration/sidekiq_unique_jobs/server/middleware_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/server/middleware_spec.rb @@ -1,30 +1,29 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Server::Middleware, redis: :redis, redis_db: 9 do let(:middleware) { SidekiqUniqueJobs::Server::Middleware.new } - let(:queue) { 'working' } + let(:queue) { "working" } - describe '#call' do - describe '#unlock' do - it 'does not unlock keys it does not own' do + describe "#call" do + describe "#unlock" do + it "does not unlock keys it does not own" do jid = UntilExecutedJob.perform_async item = Sidekiq::Queue.new(queue).find_job(jid).item - exists_key = 'uniquejobs:7f28fc7bce5b2f7ea9895080e9b2d282:EXISTS' + exists_key = "uniquejobs:7f28fc7bce5b2f7ea9895080e9b2d282:EXISTS" expect(get_key(exists_key)).to eq(jid) - set_key(exists_key, 'NOT_DELETED') + set_key(exists_key, "NOT_DELETED") middleware.call(UntilExecutedJob.new, item, queue) do - expect(get_key(exists_key)).to eq('NOT_DELETED') + expect(get_key(exists_key)).to eq("NOT_DELETED") end end end - describe ':before_yield' do - it 'removes the lock before yielding to the worker' do + describe ":before_yield" do + it "removes the lock before yielding to the worker" do jid = UntilExecutingJob.perform_async item = Sidekiq::Queue.new(queue).find_job(jid).item worker = UntilExecutingJob.new @@ -37,18 +36,18 @@ end end - describe ':after_yield' do - it 'removes the lock after yielding to the worker' do + describe ":after_yield" do + it "removes the lock after yielding to the worker" do jid = UntilExecutedJob.perform_async item = Sidekiq::Queue.new(queue).find_job(jid).item - middleware.call('UntilExecutedJob', item, queue) do + middleware.call("UntilExecutedJob", item, queue) do # NO OP end unique_keys.each do |key| - next if key.end_with?(':GRABBED') - next if key.end_with?(':EXISTS') + next if key.end_with?(":GRABBED") + next if key.end_with?(":EXISTS") expect(ttl(key)).to eq(5) end diff --git a/spec/integration/sidekiq_unique_jobs/web_spec.rb b/spec/integration/sidekiq_unique_jobs/web_spec.rb index b0aca5d9a..43093ec98 100644 --- a/spec/integration/sidekiq_unique_jobs/web_spec.rb +++ b/spec/integration/sidekiq_unique_jobs/web_spec.rb @@ -1,9 +1,8 @@ # frozen_string_literal: true -require 'spec_helper' -require 'sidekiq/web' -require 'sidekiq_unique_jobs/web' -require 'rack/test' +require "sidekiq/web" +require "sidekiq_unique_jobs/web" +require "rack/test" RSpec.describe SidekiqUniqueJobs::Web, redis: :redis do include Rack::Test::Methods @@ -16,40 +15,40 @@ def app Sidekiq.redis(&:flushdb) end - let(:digest) { 'uniquejobs:9e9b5ce5d423d3ea470977004b50ff84' } - let(:another_digest) { 'uniquejobs:24c5b03e2d49d765e5dfb2d7c51c5929' } + let(:digest) { "uniquejobs:9e9b5ce5d423d3ea470977004b50ff84" } + let(:another_digest) { "uniquejobs:24c5b03e2d49d765e5dfb2d7c51c5929" } let(:expected_digests) { [digest, another_digest] } - it 'can display digests' do + it "can display digests" do expect(MyUniqueJob.perform_async(1, 2)).not_to eq(nil) expect(MyUniqueJob.perform_async(2, 3)).not_to eq(nil) - get '/unique_digests' + get "/unique_digests" expect(last_response.status).to eq(200) expect(last_response.body).to match("/unique_digests/#{digest}") expect(last_response.body).to match("/unique_digests/#{another_digest}") end - it 'can paginate digests' do + it "can paginate digests" do 110.times do |idx| expect(MyUniqueJob.perform_async(1, idx)).not_to eq(nil) end - get '/unique_digests' + get "/unique_digests" expect(last_response.status).to eq(200) end - it 'can display digest' do + it "can display digest" do expect(MyUniqueJob.perform_async(1, 2)).not_to eq(nil) get "/unique_digests/#{digest}" expect(last_response.status).to eq(200) - expect(last_response.body).to match('uniquejobs:9e9b5ce5d423d3ea470977004b50ff84') - expect(last_response.body).to match('uniquejobs:9e9b5ce5d423d3ea470977004b50ff84:EXISTS') - expect(last_response.body).to match('uniquejobs:9e9b5ce5d423d3ea470977004b50ff84:GRABBED') + expect(last_response.body).to match("uniquejobs:9e9b5ce5d423d3ea470977004b50ff84") + expect(last_response.body).to match("uniquejobs:9e9b5ce5d423d3ea470977004b50ff84:EXISTS") + expect(last_response.body).to match("uniquejobs:9e9b5ce5d423d3ea470977004b50ff84:GRABBED") end - it 'can delete a digest' do + it "can delete a digest" do expect(MyUniqueJob.perform_async(1, 2)).not_to eq(nil) expect(MyUniqueJob.perform_async(2, 3)).not_to eq(nil) @@ -60,7 +59,7 @@ def app follow_redirect! - expect(last_request.url).to end_with('/unique_digests') + expect(last_request.url).to end_with("/unique_digests") expect(last_response.body).not_to match("/unique_digests/#{digest}") expect(last_response.body).to match("/unique_digests/#{another_digest}") diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4a4124e71..c33b1f224 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,32 +1,34 @@ # frozen_string_literal: true -if RUBY_ENGINE == 'ruby' && RUBY_VERSION >= '2.5.1' - require 'simplecov' unless %w[false 0].include?(ENV['COV']) +require "bundler/setup" + +if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.5" && RUBY_VERSION < "2.6" + require "simplecov" unless %w[false 0].include?(ENV["COV"]) begin - require 'pry' - require 'byebug' + require "pry" rescue LoadError - puts 'Pry unavailable' + puts "Pry unavailable" end end -require 'rspec' -require 'rspec/its' -require 'awesome_print' +require "rspec" +require "rspec/its" -require 'sidekiq' -require 'sidekiq/util' -require 'sidekiq-unique-jobs' -require 'timecop' -require 'sidekiq_unique_jobs/testing' +require "sidekiq" +require "sidekiq/api" +require "sidekiq/util" +require "sidekiq-unique-jobs" +require "timecop" +require "sidekiq_unique_jobs/testing" -Sidekiq.logger = Logger.new('/dev/null') +Sidekiq.logger = Logger.new("/dev/null") SidekiqUniqueJobs.logger.level = Object.const_get("Logger::#{ENV.fetch('LOGLEVEL') { 'error' }.upcase}") -require 'sidekiq/redis_connection' +require "sidekiq/redis_connection" -Dir[File.join(File.dirname(__FILE__), 'support', '**', '*.rb')].each { |f| require f } +Dir[File.join(File.dirname(__FILE__), "support", "**", "*.rb")].each { |f| require f } +Dir[File.join(File.dirname(__FILE__), "..", "examples", "**", "*.rb")].each { |f| require f } RSpec.configure do |config| config.define_derived_metadata do |meta| @@ -38,18 +40,16 @@ config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end - config.example_status_persistence_file_path = '.rspec_status' - config.filter_run :focus unless ENV['CI'] + config.example_status_persistence_file_path = ".rspec_status" + config.filter_run :focus unless ENV["CI"] config.run_all_when_everything_filtered = true config.disable_monkey_patching! config.warnings = false - config.default_formatter = 'doc' if config.files_to_run.one? + config.default_formatter = "doc" if config.files_to_run.one? config.order = :random Kernel.srand config.seed end -Dir[File.join(File.dirname(__FILE__), '..', 'examples', '**', '*.rb')].each { |f| require f } - def capture(stream) begin stream = stream.to_s diff --git a/spec/support/matchers/redis_matchers.rb b/spec/support/matchers/redis_matchers.rb index 4aa97c632..86378d1e4 100644 --- a/spec/support/matchers/redis_matchers.rb +++ b/spec/support/matchers/redis_matchers.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require 'rspec/expectations' -require 'rspec/eventually' +require "rspec/expectations" +require "rspec/eventually" RSpec::Matchers.define :be_enqueued_in do |queue| SidekiqUniqueJobs.redis do |conn| @@ -16,7 +16,7 @@ RSpec::Matchers.define :be_scheduled_at do |time| SidekiqUniqueJobs.redis do |conn| - @actual = conn.zcount('schedule', -1, time) + @actual = conn.zcount("schedule", -1, time) match do |count_in_queue| @expected = count_in_queue diff --git a/spec/support/retry.rb b/spec/support/retry.rb index f5d626fb3..ca25db8b4 100644 --- a/spec/support/retry.rb +++ b/spec/support/retry.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'rspec/retry' +require "rspec/retry" RSpec.configure do |config| # show retry status in spec process diff --git a/spec/support/ruby_meta.rb b/spec/support/ruby_meta.rb index c28a653d6..d49d91db4 100644 --- a/spec/support/ruby_meta.rb +++ b/spec/support/ruby_meta.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require_relative 'version_check' +require_relative "version_check" RSpec.configure do |config| config.before do |example| diff --git a/spec/support/shared_examples/a_lockable_lock.rb b/spec/support/shared_examples/a_lockable_lock.rb index 13d609fe7..efa0e8faf 100644 --- a/spec/support/shared_examples/a_lockable_lock.rb +++ b/spec/support/shared_examples/a_lockable_lock.rb @@ -1,60 +1,60 @@ # frozen_string_literal: true -RSpec.shared_examples 'a lock implementation' do - it 'can be locked' do +RSpec.shared_examples "a lock implementation" do + it "can be locked" do expect(process_one.lock).to eq(jid_one) end - context 'when process one has locked the job' do + context "when process one has locked the job" do before { process_one.lock } - it 'has locked process_one' do + it "has locked process_one" do expect(process_one).to be_locked end - it 'prevents process_two from locking' do + it "prevents process_two from locking" do expect(process_two.lock).to eq(nil) end - it 'prevents process_two from executing' do + it "prevents process_two from executing" do expect(process_two.execute {}).to eq(nil) end end end -RSpec.shared_examples 'an executing lock implementation' do - context 'when job has not been locked' do - it 'does not execute' do +RSpec.shared_examples "an executing lock implementation" do + context "when job has not been locked" do + it "does not execute" do unset = true process_one.execute { unset = false } expect(unset).to eq(true) end end - context 'when process_one executes the job' do + context "when process_one executes the job" do before { process_one.lock } - it 'keeps being locked while executing' do + it "keeps being locked while executing" do process_one.execute do expect(process_one).to be_locked end end - it 'keeps being locked when an error is raised' do - expect { process_one.execute { raise 'Hell' } } - .to raise_error('Hell') + it "keeps being locked when an error is raised" do + expect { process_one.execute { raise "Hell" } } + .to raise_error("Hell") expect(process_one).to be_locked end - it 'prevents process_two from locking' do + it "prevents process_two from locking" do process_one.execute do expect(process_two.lock).to eq(nil) expect(process_two).not_to be_locked end end - it 'prevents process_two from executing' do + it "prevents process_two from executing" do process_one.execute do unset = true process_two.execute { unset = false } diff --git a/spec/support/shared_examples/a_performing_worker.rb b/spec/support/shared_examples/a_performing_worker.rb index a2b94bc42..ab825478d 100644 --- a/spec/support/shared_examples/a_performing_worker.rb +++ b/spec/support/shared_examples/a_performing_worker.rb @@ -1,24 +1,25 @@ # frozen_string_literal: true -RSpec.shared_examples 'a performing worker' do |splat_arguments: true| - let(:worker_instance) { instance_spy(described_class) } +RSpec.shared_examples "a performing worker" do |splat_arguments: true| + let(:worker_instance) { described_class.new } before do allow(described_class).to receive(:new).and_return(worker_instance) + allow(worker_instance).to receive(:perform).with(any_args) end - it 'receives the expected arguments' do + it "receives the expected arguments" do SidekiqUniqueJobs.use_config(enabled: false) do Sidekiq::Testing.inline! do if args == no_args - expect(worker_instance).to receive(:perform).with(no_args) described_class.perform_async + expect(worker_instance).to have_received(:perform).with(no_args) elsif splat_arguments - expect(worker_instance).to receive(:perform).with(*args) described_class.perform_async(*args) + expect(worker_instance).to have_received(:perform).with(*args) else - expect(worker_instance).to receive(:perform).with(args) described_class.perform_async(args) + expect(worker_instance).to have_received(:perform).with(args) end end end diff --git a/spec/support/shared_examples/an_executing_lock_with_error_handling.rb b/spec/support/shared_examples/an_executing_lock_with_error_handling.rb index 599bd59f0..43e2afe7c 100644 --- a/spec/support/shared_examples/an_executing_lock_with_error_handling.rb +++ b/spec/support/shared_examples/an_executing_lock_with_error_handling.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.shared_examples 'an executing lock with error handling' do +RSpec.shared_examples "an executing lock with error handling" do subject(:execute) { lock.execute(&block) } let(:block) { -> {} } @@ -18,12 +18,12 @@ allow(lock).to receive(:log_fatal) end - context 'when yield fails with other errors' do - let(:block) { -> { raise 'HELL' } } + context "when yield fails with other errors" do + let(:block) { -> { raise "HELL" } } let(:locked?) { nil } it 'raises "HELL"' do - expect { execute }.to raise_error('HELL') + expect { execute }.to raise_error("HELL") expect(lock).not_to have_received(:unlock) end diff --git a/spec/support/shared_examples/sidekiq_with_options.rb b/spec/support/shared_examples/sidekiq_with_options.rb index 42ae7deb5..33dfe3dfc 100644 --- a/spec/support/shared_examples/sidekiq_with_options.rb +++ b/spec/support/shared_examples/sidekiq_with_options.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.shared_examples 'sidekiq with options' do +RSpec.shared_examples "sidekiq with options" do subject(:sidekiq_options) { described_class.get_sidekiq_options } it { is_expected.to match(a_hash_including(options)) } diff --git a/spec/support/shared_examples/with_a_stubbed_locksmith.rb b/spec/support/shared_examples/with_a_stubbed_locksmith.rb index 2c73bd185..c3323b0f9 100644 --- a/spec/support/shared_examples/with_a_stubbed_locksmith.rb +++ b/spec/support/shared_examples/with_a_stubbed_locksmith.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.shared_context 'with a stubbed locksmith' do +RSpec.shared_context "with a stubbed locksmith" do let(:locksmith) { instance_double(SidekiqUniqueJobs::Locksmith) } let(:redis_pool) { nil } diff --git a/spec/support/sidekiq_helpers.rb b/spec/support/sidekiq_helpers.rb index 20d7ba477..fbe9052c8 100644 --- a/spec/support/sidekiq_helpers.rb +++ b/spec/support/sidekiq_helpers.rb @@ -4,7 +4,7 @@ module SidekiqHelpers include SidekiqUniqueJobs::Connection def dead_count - zcard('dead') + zcard("dead") end def get_key(key) @@ -32,7 +32,7 @@ def queue_count(queue) end def retry_count - zcard('retry') + zcard("retry") end def scard(queue) @@ -40,11 +40,11 @@ def scard(queue) end def schedule_count - zcard('schedule') + zcard("schedule") end def schedule_count_at(max = Time.now.to_f + 2 * 60) - zcount('schedule', '-inf', max) + zcount("schedule", "-inf", max) end def set_key(key, value) @@ -56,7 +56,7 @@ def ttl(key) end def unique_digests - smembers('unique:keys') + smembers("unique:keys") end def smembers(key) @@ -64,7 +64,7 @@ def smembers(key) end def unique_keys - keys('uniquejobs:*') + keys("uniquejobs:*") end def zadd(queue, timestamp, item) @@ -75,7 +75,7 @@ def zcard(queue) redis { |conn| conn.zcard(queue) } end - def zcount(queue, min = '-inf', max = '+inf') + def zcount(queue, min = "-inf", max = "+inf") redis { |conn| conn.zcount(queue, min, max) } end end diff --git a/spec/support/sidekiq_meta.rb b/spec/support/sidekiq_meta.rb index a122d91e1..c500c3910 100644 --- a/spec/support/sidekiq_meta.rb +++ b/spec/support/sidekiq_meta.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require 'sidekiq/testing' +require "sidekiq/testing" -require_relative 'version_check' +require_relative "version_check" RSpec.configure do |config| config.before(:each, redis: :redis) do |example| diff --git a/spec/support/version_check.rb b/spec/support/version_check.rb index c1da3c14e..456a7c606 100644 --- a/spec/support/version_check.rb +++ b/spec/support/version_check.rb @@ -13,8 +13,8 @@ def initialize(version, constraint) @operator2 = match[:operator2] end - fail ArgumentError, 'A version (5.0) is required to compare against' unless @version - fail ArgumentError, 'At least one operator and version is required (<>= 5.1)' unless @operator1 + raise ArgumentError, "A version (5.0) is required to compare against" unless @version + raise ArgumentError, "At least one operator and version is required (<>= 5.1)" unless @operator1 end def invalid? diff --git a/spec/unit/sidekiq_unique_jobs/cli_spec.rb b/spec/unit/sidekiq_unique_jobs/cli_spec.rb index 353ecfe4e..378ea466e 100644 --- a/spec/unit/sidekiq_unique_jobs/cli_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/cli_spec.rb @@ -1,26 +1,24 @@ # frozen_string_literal: true -require 'spec_helper' +require "thor/runner" +require "irb" -require 'thor/runner' -require 'irb' - -RSpec.describe SidekiqUniqueJobs::Cli, redis: :redis, ruby_ver: '>= 2.4' do +RSpec.describe SidekiqUniqueJobs::Cli, redis: :redis, ruby_ver: ">= 2.4" do let(:item) do { - 'jid' => jid, - 'unique_digest' => unique_key, + "jid" => jid, + "unique_digest" => unique_key, } end - let(:jid) { 'abcdefab' } - let(:unique_key) { 'uniquejobs:abcdefab' } + let(:jid) { "abcdefab" } + let(:unique_key) { "uniquejobs:abcdefab" } let(:max_lock_time) { 1 } - let(:pattern) { '*' } + let(:pattern) { "*" } - describe '#help' do + describe "#help" do subject(:help) { capture(:stdout) { described_class.start(%w[help]) } } - it 'displays help' do + it "displays help" do expect(help).to include <<~HEADER Commands: jobs console # drop into a console with easy access to helper methods @@ -30,10 +28,10 @@ HEADER end - describe '#help del' do + describe "#help del" do subject(:help) { capture(:stdout) { described_class.start(%w[help del]) } } - it 'displays help about the `del` command' do + it "displays help about the `del` command" do expect(help).to eq <<~HEADER Usage: jobs del PATTERN @@ -48,10 +46,10 @@ end end - describe '#help keys' do + describe "#help keys" do subject(:help) { capture(:stdout) { described_class.start(%w[help keys]) } } - it 'displays help about the `key` command' do + it "displays help about the `key` command" do expect(help).to eq <<~HEADER Usage: jobs keys PATTERN @@ -66,27 +64,27 @@ end end - describe '.keys' do + describe ".keys" do subject(:keys) { capture(:stdout) { described_class.start(%w[keys * --count 1000]) } } - context 'when no keys exist' do + context "when no keys exist" do it { is_expected.to eq("Found 0 keys matching '#{pattern}':\n") } end - context 'when a key exists' do + context "when a key exists" do before do SidekiqUniqueJobs::Locksmith.new(item).lock end - after { SidekiqUniqueJobs::Util.del('*', 1000) } + after { SidekiqUniqueJobs::Util.del("*", 1000) } it { is_expected.to include("Found 2 keys matching '*':") } - it { is_expected.to include('uniquejobs:abcdefab:EXISTS') } - it { is_expected.to include('uniquejobs:abcdefab:GRABBED') } + it { is_expected.to include("uniquejobs:abcdefab:EXISTS") } + it { is_expected.to include("uniquejobs:abcdefab:GRABBED") } end end - describe '.del' do + describe ".del" do subject(:del) { capture(:stdout) { described_class.start(args) } } let(:args) { %W[del * #{options} --count 1000] } @@ -95,8 +93,8 @@ SidekiqUniqueJobs::Locksmith.new(item).lock end - context 'with argument --dry-run' do - let(:options) { '--dry-run' } + context "with argument --dry-run" do + let(:options) { "--dry-run" } specify do expect(del).to eq("Would delete 2 keys matching '*'\n") @@ -104,8 +102,8 @@ end end - context 'with argument --no-dry-run' do - let(:options) { '--no-dry-run' } + context "with argument --no-dry-run" do + let(:options) { "--no-dry-run" } specify do expect(del).to eq("Deleted 2 keys matching '*'\n") @@ -114,17 +112,21 @@ end end - describe '.console', ruby_ver: '>= 2.5.1' do + describe ".console" do subject(:console) { capture(:stdout) { described_class.start(%w[console]) } } + let(:console_class) { defined?(Pry) ? Pry : IRB } + specify do - expect(Object).to receive(:include).with(SidekiqUniqueJobs::Util).and_return(true) - allow(Pry).to receive(:start).and_return(true) + allow(Object).to receive(:include) + allow(console_class).to receive(:start).and_return(true) expect(console).to eq <<~HEADER Use `keys '*', 1000 to display the first 1000 unique keys matching '*' Use `del '*', 1000, true (default) to see how many keys would be deleted for the pattern '*' Use `del '*', 1000, false to delete the first 1000 keys matching '*' HEADER + + expect(Object).to have_received(:include).with(SidekiqUniqueJobs::Util) end end end diff --git a/spec/unit/sidekiq_unique_jobs/client/middleware_spec.rb b/spec/unit/sidekiq_unique_jobs/client/middleware_spec.rb index b14584ed4..6bb379cf5 100644 --- a/spec/unit/sidekiq_unique_jobs/client/middleware_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/client/middleware_spec.rb @@ -1,44 +1,42 @@ # frozen_string_literal: true -require 'spec_helper' - -require 'sidekiq/worker' -require 'sidekiq-unique-jobs' +require "sidekiq/worker" +require "sidekiq-unique-jobs" # rubocop:disable RSpec/InstanceVariable RSpec.describe SidekiqUniqueJobs::Client::Middleware do let(:middleware) { described_class.new } - describe '#call' do + describe "#call" do subject(:call) { middleware.call(worker_class, item, queue, &block) } let(:block) { -> { @inside_block_value = true } } let(:worker_class) { SimpleWorker } - let(:queue) { 'default' } + let(:queue) { "default" } let(:item) do - { 'class' => SimpleWorker, - 'queue' => queue, - 'args' => [1] } + { "class" => SimpleWorker, + "queue" => queue, + "args" => [1] } end before { @inside_block_value = false } - context 'when locking succeeds' do + context "when locking succeeds" do before do allow(middleware).to receive(:locked?).and_return(true) end - it 'yields control' do + it "yields control" do expect { call }.to change { @inside_block_value }.to(true) end end - context 'when already locked' do + context "when already locked" do before do allow(middleware).to receive(:locked?).and_return(false) end - it 'does not yield control' do + it "does not yield control" do expect { call }.not_to change { @inside_block_value }.from(false) end end diff --git a/spec/unit/sidekiq_unique_jobs/core_ext_spec.rb b/spec/unit/sidekiq_unique_jobs/core_ext_spec.rb index 3305c2ff4..207054dc2 100644 --- a/spec/unit/sidekiq_unique_jobs/core_ext_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/core_ext_spec.rb @@ -1,29 +1,28 @@ # frozen_string_literal: true -require 'spec_helper' - -RSpec.describe 'core_ext.rb' do +require "spec_helper" +RSpec.describe "core_ext.rb" do describe Hash do let(:hash) { { test: :me, not: :me } } - describe '#slice' do + describe "#slice" do specify { expect(hash.slice(:test)).to eq(test: :me) } end - describe '#slice!' do + describe "#slice!" do specify { expect { hash.slice!(:test) }.to change { hash }.to(test: :me) } end - describe '#stringify_keys' do + describe "#stringify_keys" do subject(:stringify_keys) { hash.stringify_keys } - it { is_expected.to eq('test' => :me, 'not' => :me) } + it { is_expected.to eq("test" => :me, "not" => :me) } end - describe '#transform_keys' do + describe "#transform_keys" do subject(:transform_keys) { hash.transform_keys(&:to_s) } - it { is_expected.to eq('test' => :me, 'not' => :me) } + it { is_expected.to eq("test" => :me, "not" => :me) } end end @@ -31,16 +30,16 @@ let(:array) { [1, 2, nil, last_argument] } let(:last_argument) { Object.new } - describe '#extract_options!' do + describe "#extract_options!" do subject(:extract_options!) { array.extract_options! } - context 'when last argument is a hash' do + context "when last argument is a hash" do let(:last_argument) { { test: :me, not: :me } } it { is_expected.to eq(last_argument) } end - context 'when last argument is not a hash' do + context "when last argument is not a hash" do let(:last_argument) { nil } it { is_expected.to eq({}) } diff --git a/spec/unit/sidekiq_unique_jobs/digests_spec.rb b/spec/unit/sidekiq_unique_jobs/digests_spec.rb index e68cf4ca3..bf2c84db0 100644 --- a/spec/unit/sidekiq_unique_jobs/digests_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/digests_spec.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Digests, redis: :redis do before do (1..10).each do |arg| @@ -24,13 +23,13 @@ ] end - describe '.all' do - subject(:all) { described_class.all(pattern: '*', count: 1000) } + describe ".all" do + subject(:all) { described_class.all(pattern: "*", count: 1000) } it { is_expected.to match_array(expected_keys) } end - describe '.del' do + describe ".del" do subject(:del) { described_class.del(digest: digest, pattern: pattern, count: count) } let(:digest) { nil } @@ -41,33 +40,33 @@ allow(described_class).to receive(:log_info) end - context 'when given a pattern' do - let(:pattern) { '*' } + context "when given a pattern" do + let(:pattern) { "*" } - it 'deletes all matching digests' do + it "deletes all matching digests" do expect(del).to eq(10) expect(described_class.all).to match_array([]) end - it 'logs performance info' do + it "logs performance info" do del expect(described_class) .to have_received(:log_info).with( - a_string_starting_with('delete_by_pattern(*, count: 1000)') + a_string_starting_with("delete_by_pattern(*, count: 1000)") .and(matching(/completed in (\d\.\d+)ms/)), ) end end - context 'when given a digest' do + context "when given a digest" do let(:digest) { expected_keys.last } - it 'deletes just the specific digest' do + it "deletes just the specific digest" do expect(del).to eq(9) expect(described_class.all).to match_array(expected_keys - [digest]) end - it 'logs performance info' do + it "logs performance info" do del expect(described_class).to have_received(:log_info) .with( diff --git a/spec/unit/sidekiq_unique_jobs/lock/base_lock_spec.rb b/spec/unit/sidekiq_unique_jobs/lock/base_lock_spec.rb index 02246790a..d2fe1d94f 100644 --- a/spec/unit/sidekiq_unique_jobs/lock/base_lock_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/lock/base_lock_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::BaseLock do - include_context 'with a stubbed locksmith' - let(:lock) { described_class.new(item, callback) } - let(:callback) { -> {} } - let(:unique_digest) { 'woohoounique' } + include_context "with a stubbed locksmith" + let(:lock) { described_class.new(item, callback) } + let(:callback) { -> {} } + let(:unique_digest) { "woohoounique" } let(:item) do { - 'jid' => 'maaaahjid', - 'queue' => 'default', - 'class' => 'UntilExecutedJob', - 'lock' => :until_executed, - 'args' => [1], + "jid" => "maaaahjid", + "queue" => "default", + "class" => "UntilExecutedJob", + "lock" => :until_executed, + "args" => [1], } end @@ -23,30 +22,30 @@ def execute end end - describe '#lock' do + describe "#lock" do subject(:lock_lock) { lock.lock } - context 'when already locked?' do + context "when already locked?" do before do allow(lock).to receive(:locked?).and_return(true) end - it { is_expected.to eq('maaaahjid') } + it { is_expected.to eq("maaaahjid") } end - context 'when not locked?' do + context "when not locked?" do before do allow(lock).to receive(:locked?).and_return(false) allow(locksmith).to receive(:lock).with(kind_of(Integer)).and_return(token) end - context 'when a token is retrieved' do - let(:token) { 'another jid' } + context "when a token is retrieved" do + let(:token) { "another jid" } - it { is_expected.to eq('another jid') } + it { is_expected.to eq("another jid") } end - context 'when token is not retrieved' do + context "when token is not retrieved" do let(:token) { nil } it { is_expected.to eq(nil) } @@ -54,55 +53,55 @@ def execute end end - describe '#execute' do + describe "#execute" do it do expect { lock.execute } .to raise_error(NotImplementedError, "#execute needs to be implemented in #{described_class}") end - context 'when an implementation raises Sidekiq::Shutdown while excuting' do + context "when an implementation raises Sidekiq::Shutdown while excuting" do let(:lock) { FailedExecutingLock.new(item, callback) } it do allow(lock).to receive(:unlock_with_callback) allow(lock).to receive(:log_info) - expect { lock.execute { raise Sidekiq::Shutdown, 'boohoo' } } - .to raise_error(Sidekiq::Shutdown, 'boohoo') + expect { lock.execute { raise Sidekiq::Shutdown, "boohoo" } } + .to raise_error(Sidekiq::Shutdown, "boohoo") expect(lock).not_to have_received(:unlock_with_callback) expect(lock).to have_received(:log_info) - .with('Sidekiq is shutting down, the job `should` be put back on the queue. Keeping the lock!') + .with("Sidekiq is shutting down, the job `should` be put back on the queue. Keeping the lock!") end end end - describe '#unlock' do + describe "#unlock" do subject(:unlock) { lock.unlock } before do - allow(locksmith).to receive(:unlock).with(item['jid']).and_return('unlocked') + allow(locksmith).to receive(:unlock).with(item["jid"]).and_return("unlocked") end - it { is_expected.to eq('unlocked') } + it { is_expected.to eq("unlocked") } end - describe '#delete' do + describe "#delete" do subject { lock.delete } - before { allow(locksmith).to receive(:delete).and_return('deleted') } + before { allow(locksmith).to receive(:delete).and_return("deleted") } - it { is_expected.to eq('deleted') } + it { is_expected.to eq("deleted") } end - describe '#delete!' do + describe "#delete!" do subject { lock.delete! } - before { allow(locksmith).to receive(:delete!).and_return('deleted') } + before { allow(locksmith).to receive(:delete!).and_return("deleted") } - it { is_expected.to eq('deleted') } + it { is_expected.to eq("deleted") } end - describe '#locked?' do + describe "#locked?" do it do allow(locksmith).to receive(:locked?).and_return(true) diff --git a/spec/unit/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb b/spec/unit/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb index 7d9768445..f92627e08 100644 --- a/spec/unit/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/lock/until_and_while_executing_spec.rb @@ -1,21 +1,20 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::UntilAndWhileExecuting do - include_context 'with a stubbed locksmith' + include_context "with a stubbed locksmith" let(:lock) { described_class.new(item, callback) } let(:callback) { -> {} } let(:item) do { - 'jid' => 'maaaahjid', - 'class' => 'UntilAndWhileExecutingJob', - 'lock' => 'until_and_while_executing', - 'args' => ['one'], + "jid" => "maaaahjid", + "class" => "UntilAndWhileExecutingJob", + "lock" => "until_and_while_executing", + "args" => ["one"], } end - describe '#execute' do + describe "#execute" do let(:runtime_lock) { instance_spy(SidekiqUniqueJobs::Lock::WhileExecuting) } before do @@ -25,10 +24,10 @@ allow(runtime_lock).to receive(:execute).and_yield end - context 'when locked?' do + context "when locked?" do let(:locked?) { true } - it 'unlocks the unique key before yielding' do + it "unlocks the unique key before yielding" do inside_block_value = false lock.execute { inside_block_value = true } @@ -40,10 +39,10 @@ end end - context 'when not locked?' do + context "when not locked?" do let(:locked?) { false } - it 'unlocks the unique key before yielding' do + it "unlocks the unique key before yielding" do inside_block_value = false lock.execute { inside_block_value = true } expect(inside_block_value).to eq(false) @@ -55,12 +54,12 @@ end end - describe '#runtime_lock' do + describe "#runtime_lock" do subject(:runtime_lock) { lock.runtime_lock } it { is_expected.to be_a(SidekiqUniqueJobs::Lock::WhileExecuting) } - it 'initializes with the right arguments' do + it "initializes with the right arguments" do allow(SidekiqUniqueJobs::Lock::WhileExecuting).to receive(:new) runtime_lock diff --git a/spec/unit/sidekiq_unique_jobs/lock/until_executed_spec.rb b/spec/unit/sidekiq_unique_jobs/lock/until_executed_spec.rb index 0a31eb379..a9a3965bb 100644 --- a/spec/unit/sidekiq_unique_jobs/lock/until_executed_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/lock/until_executed_spec.rb @@ -1,26 +1,25 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::UntilExecuted do - include_context 'with a stubbed locksmith' + include_context "with a stubbed locksmith" let(:lock) { described_class.new(item, callback) } let(:callback) { -> {} } let(:item) do { - 'jid' => 'maaaahjid', - 'class' => 'UntilExecutedJob', - 'lock' => 'until_executed', - 'args' => %w[one two], + "jid" => "maaaahjid", + "class" => "UntilExecutedJob", + "lock" => "until_executed", + "args" => %w[one two], } end - describe '#execute' do - it_behaves_like 'an executing lock with error handling' do - context 'when not initially locked?' do + describe "#execute" do + it_behaves_like "an executing lock with error handling" do + context "when not initially locked?" do let(:initially_locked?) { false } - it 'returns without yielding' do + it "returns without yielding" do execute expect(callback).not_to have_received(:call) @@ -28,26 +27,26 @@ end end - context 'when lock is not locked?' do - let(:block) { -> { raise 'HELL' } } + context "when lock is not locked?" do + let(:block) { -> { raise "HELL" } } let(:locked?) { nil } - it 'calls back' do - expect { execute }.to raise_error('HELL') + it "calls back" do + expect { execute }.to raise_error("HELL") expect(callback).not_to have_received(:call) end end - context 'when callback raises error' do - let(:callback) { -> { raise 'CallbackError' } } + context "when callback raises error" do + let(:callback) { -> { raise "CallbackError" } } let(:locked?) { false } - it 'logs a warning' do - expect { execute }.to raise_error('CallbackError') + it "logs a warning" do + expect { execute }.to raise_error("CallbackError") expect(lock).to have_received(:log_warn) - .with('unlocked successfully but the #after_unlock callback failed!') + .with("unlocked successfully but the #after_unlock callback failed!") end end end diff --git a/spec/unit/sidekiq_unique_jobs/lock/until_executing_spec.rb b/spec/unit/sidekiq_unique_jobs/lock/until_executing_spec.rb index 6ce207c3a..3ea1fdae9 100644 --- a/spec/unit/sidekiq_unique_jobs/lock/until_executing_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/lock/until_executing_spec.rb @@ -1,19 +1,18 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::UntilExecuting do - include_context 'with a stubbed locksmith' + include_context "with a stubbed locksmith" let(:lock) { described_class.new(item, callback) } let(:callback) { -> {} } let(:item) do - { 'jid' => 'maaaahjid', - 'class' => 'UntilExpiredJob', - 'lock' => 'until_timeout' } + { "jid" => "maaaahjid", + "class" => "UntilExpiredJob", + "lock" => "until_timeout" } end - describe '#execute' do - it 'calls the callback' do + describe "#execute" do + it "calls the callback" do allow(lock).to receive(:unlock_with_callback) expect { |block| lock.execute(&block) }.to yield_control diff --git a/spec/unit/sidekiq_unique_jobs/lock/until_expired_spec.rb b/spec/unit/sidekiq_unique_jobs/lock/until_expired_spec.rb index 991d32929..b572c2509 100644 --- a/spec/unit/sidekiq_unique_jobs/lock/until_expired_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/lock/until_expired_spec.rb @@ -1,28 +1,27 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::UntilExpired do - include_context 'with a stubbed locksmith' + include_context "with a stubbed locksmith" let(:lock) { described_class.new(item, callback) } let(:callback) { -> {} } let(:item) do - { 'jid' => 'maaaahjid', - 'class' => 'UntilExpiredJob', - 'lock' => 'until_timeout' } + { "jid" => "maaaahjid", + "class" => "UntilExpiredJob", + "lock" => "until_timeout" } end before do allow(callback).to receive(:call) end - describe '#unlock' do + describe "#unlock" do subject(:unlock) { lock.unlock } it { is_expected.to eq(true) } end - describe '#execute' do + describe "#execute" do subject(:execute) { lock.execute(&block) } let(:locked?) { false } @@ -31,16 +30,16 @@ allow(lock).to receive(:locked?).and_return(locked?) end - context 'when locked?' do + context "when locked?" do let(:locked?) { true } - it 'yields to caller' do + it "yields to caller" do expect { |block| lock.execute(&block) }.to yield_control end end - context 'when not locked?' do - it 'does not yield to caller' do + context "when not locked?" do + it "does not yield to caller" do expect { |block| lock.execute(&block) }.not_to yield_control end end diff --git a/spec/unit/sidekiq_unique_jobs/lock/while_executing_reject_spec.rb b/spec/unit/sidekiq_unique_jobs/lock/while_executing_reject_spec.rb index 0fb93fec0..e50121654 100644 --- a/spec/unit/sidekiq_unique_jobs/lock/while_executing_reject_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/lock/while_executing_reject_spec.rb @@ -1,29 +1,28 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::WhileExecutingReject do - include_context 'with a stubbed locksmith' + include_context "with a stubbed locksmith" let(:lock) { described_class.new(item, callback) } let(:callback) { -> {} } let(:item) do - { 'jid' => 'maaaahjid', - 'class' => 'WhileExecutingRejectJob', - 'lock' => 'while_executing_reject', - 'args' => [%w[array of arguments]] } + { "jid" => "maaaahjid", + "class" => "WhileExecutingRejectJob", + "lock" => "while_executing_reject", + "args" => [%w[array of arguments]] } end before do allow(lock).to receive(:unlock) end - describe '#lock' do + describe "#lock" do subject { lock.lock } it { is_expected.to eq(true) } end - describe '#execute' do + describe "#execute" do subject(:execute) { lock.execute {} } let(:token) { nil } @@ -33,19 +32,19 @@ allow(lock).to receive(:with_cleanup).and_yield end - context 'when lock succeeds' do - let(:token) { 'a token' } + context "when lock succeeds" do + let(:token) { "a token" } - it 'processes the job' do + it "processes the job" do execute expect(lock).to have_received(:with_cleanup) end end - context 'when lock fails' do + context "when lock fails" do let(:token) { nil } - it 'rejects the job' do + it "rejects the job" do execute expect(lock).not_to have_received(:with_cleanup) diff --git a/spec/unit/sidekiq_unique_jobs/lock/while_executing_spec.rb b/spec/unit/sidekiq_unique_jobs/lock/while_executing_spec.rb index 4246d14fb..d18bf125a 100644 --- a/spec/unit/sidekiq_unique_jobs/lock/while_executing_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/lock/while_executing_spec.rb @@ -1,34 +1,33 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Lock::WhileExecuting do - include_context 'with a stubbed locksmith' + include_context "with a stubbed locksmith" let(:lock) { described_class.new(item, callback) } let(:callback) { -> {} } let(:item) do - { 'jid' => 'maaaahjid', - 'class' => 'WhileExecutingJob', - 'lock' => 'while_executing', - 'args' => [%w[array of arguments]] } + { "jid" => "maaaahjid", + "class" => "WhileExecutingJob", + "lock" => "while_executing", + "args" => [%w[array of arguments]] } end - describe '.new' do + describe ".new" do specify do expect { described_class.new(item, callback) } - .to change { item['unique_digest'] } - .to a_string_ending_with(':RUN') + .to change { item["unique_digest"] } + .to a_string_ending_with(":RUN") end end - describe '#lock' do + describe "#lock" do subject { lock.lock } it { is_expected.to eq(true) } end - describe '#execute' do + describe "#execute" do subject(:execute) { lock.execute } before do @@ -41,7 +40,7 @@ # it_behaves_like 'an executing lock with error handling' # end - context 'when lock fails' do + context "when lock fails" do let(:token) { nil } it do diff --git a/spec/unit/sidekiq_unique_jobs/middleware_spec.rb b/spec/unit/sidekiq_unique_jobs/middleware_spec.rb index 82cb16d73..efc676d89 100644 --- a/spec/unit/sidekiq_unique_jobs/middleware_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/middleware_spec.rb @@ -1,46 +1,57 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Middleware do describe SidekiqUniqueJobs do - describe '.configure_middleware' do - it 'configures both client and server middleware' do - expect(described_class).to receive(:configure_server_middleware) - expect(described_class).to receive(:configure_client_middleware) + let(:client_config) { class_double(Sidekiq) } + let(:server_config) { class_double(Sidekiq) } + let(:client_middleware) { instance_spy(Sidekiq::Middleware::Chain) } + let(:server_middleware) { instance_spy(Sidekiq::Middleware::Chain) } + + before do + allow(Sidekiq).to receive(:configure_client).and_yield(client_config) + allow(Sidekiq).to receive(:configure_server).and_yield(server_config) + + allow(client_config).to receive(:client_middleware).and_yield(client_middleware) - described_class.configure_middleware + allow(server_config).to receive(:client_middleware).and_yield(client_middleware) + allow(server_config).to receive(:server_middleware).and_yield(server_middleware) + end + + shared_examples "configures client" do + it "adds client middleware when required" do + expect(client_config).to have_received(:client_middleware) + expect(client_middleware).to have_received(:add).with(SidekiqUniqueJobs::Client::Middleware).at_least(:once) end end - describe '.configure_server_middleware' do - let(:server_config) { class_double(Sidekiq) } - let(:server_middleware) { instance_double(Sidekiq::Middleware::Chain) } - let(:client_middleware) { instance_double(Sidekiq::Middleware::Chain) } + shared_examples "configures server" do + it "adds client and server middleware when required" do + expect(server_config).to have_received(:client_middleware).at_least(:once) + expect(client_middleware).to have_received(:add).with(SidekiqUniqueJobs::Client::Middleware).at_least(:once) - it 'adds client and server middleware when required' do - expect(Sidekiq).to receive(:configure_server).and_yield(server_config) + expect(server_config).to have_received(:server_middleware) + expect(server_middleware).to have_received(:add).with(SidekiqUniqueJobs::Server::Middleware) + end + end - expect(server_config).to receive(:client_middleware).and_yield(client_middleware) - expect(client_middleware).to receive(:add).with(SidekiqUniqueJobs::Client::Middleware) + describe ".configure_middleware" do + before { described_class.configure_middleware } - expect(server_config).to receive(:server_middleware).and_yield(server_middleware) - expect(server_middleware).to receive(:add).with(SidekiqUniqueJobs::Server::Middleware) - described_class.configure_server_middleware - end + it_behaves_like "configures client" + it_behaves_like "configures server" end - describe '.configure_client_middleware' do - let(:client_config) { class_double(Sidekiq) } - let(:client_middleware) { instance_double(Sidekiq::Middleware::Chain) } + describe ".configure_server_middleware" do + before { described_class.configure_server_middleware } - it 'adds client middleware when required' do - expect(Sidekiq).to receive(:configure_client).and_yield(client_config) - expect(client_config).to receive(:client_middleware).and_yield(client_middleware) - expect(client_middleware).to receive(:add).with(SidekiqUniqueJobs::Client::Middleware) + it_behaves_like "configures server" + end - described_class.configure_client_middleware - end + describe ".configure_client_middleware" do + before { described_class.configure_client_middleware } + + it_behaves_like "configures client" end end end diff --git a/spec/unit/sidekiq_unique_jobs/normalizer_spec.rb b/spec/unit/sidekiq_unique_jobs/normalizer_spec.rb index f98bf8dee..98023fe99 100644 --- a/spec/unit/sidekiq_unique_jobs/normalizer_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/normalizer_spec.rb @@ -1,18 +1,17 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Normalizer do - describe '.jsonify' do + describe ".jsonify" do specify do original = [1, :test, [test: :test]] - expected = [1, 'test', ['test' => 'test']] + expected = [1, "test", ["test" => "test"]] expect(described_class.jsonify(original)).to eq(expected) end specify do original = [1, :test, [test: [test: :test]]] - expected = [1, 'test', ['test' => ['test' => 'test']]] + expected = [1, "test", ["test" => ["test" => "test"]]] expect(described_class.jsonify(original)).to eq(expected) end end diff --git a/spec/unit/sidekiq_unique_jobs/on_conflict/log_spec.rb b/spec/unit/sidekiq_unique_jobs/on_conflict/log_spec.rb index 8457b5702..75e2b0ad5 100644 --- a/spec/unit/sidekiq_unique_jobs/on_conflict/log_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/on_conflict/log_spec.rb @@ -1,16 +1,15 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::OnConflict::Log do let(:strategy) { described_class.new(item) } - let(:unique_digest) { 'uniquejobs:random-digest-value' } - let(:jid) { 'arandomjid' } + let(:unique_digest) { "uniquejobs:random-digest-value" } + let(:jid) { "arandomjid" } let(:item) do - { 'unique_digest' => unique_digest, 'jid' => jid } + { "unique_digest" => unique_digest, "jid" => jid } end - describe '#call' do + describe "#call" do it do allow(strategy).to receive(:log_info) strategy.call @@ -20,7 +19,7 @@ end end - describe '#replace?' do + describe "#replace?" do subject { strategy.replace? } it { is_expected.to eq(false) } diff --git a/spec/unit/sidekiq_unique_jobs/on_conflict/raise_spec.rb b/spec/unit/sidekiq_unique_jobs/on_conflict/raise_spec.rb index e5d1f5089..1976cba64 100644 --- a/spec/unit/sidekiq_unique_jobs/on_conflict/raise_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/on_conflict/raise_spec.rb @@ -1,26 +1,25 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::OnConflict::Raise do let(:strategy) { described_class.new(item) } - let(:unique_digest) { 'uniquejobs:random-digest-value' } + let(:unique_digest) { "uniquejobs:random-digest-value" } let(:item) do - { 'unique_digest' => unique_digest } + { "unique_digest" => unique_digest } end - describe '#call' do + describe "#call" do let(:call) { strategy.call } it do expect { call }.to raise_error( SidekiqUniqueJobs::Conflict, - 'Item with the key: uniquejobs:random-digest-value is already scheduled or processing', + "Item with the key: uniquejobs:random-digest-value is already scheduled or processing", ) end end - describe '#replace?' do + describe "#replace?" do subject { strategy.replace? } it { is_expected.to eq(false) } diff --git a/spec/unit/sidekiq_unique_jobs/on_conflict/reject_spec.rb b/spec/unit/sidekiq_unique_jobs/on_conflict/reject_spec.rb index f97871ed4..df929de10 100644 --- a/spec/unit/sidekiq_unique_jobs/on_conflict/reject_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/on_conflict/reject_spec.rb @@ -1,17 +1,16 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::OnConflict::Reject do - include_context 'with a stubbed locksmith' + include_context "with a stubbed locksmith" let(:strategy) { described_class.new(item) } let(:deadset) { instance_spy(Sidekiq::DeadSet) } - let(:payload) { instance_spy('payload') } + let(:payload) { instance_spy("payload") } let(:item) do - { 'jid' => 'maaaahjid', - 'class' => 'WhileExecutingRejectJob', - 'lock' => 'while_executing_reject', - 'args' => [%w[array of arguments]] } + { "jid" => "maaaahjid", + "class" => "WhileExecutingRejectJob", + "lock" => "while_executing_reject", + "args" => [%w[array of arguments]] } end before do @@ -19,71 +18,91 @@ allow(strategy).to receive(:payload).and_return(payload) end - describe '#replace?' do + describe "#replace?" do subject { strategy.replace? } it { is_expected.to eq(false) } end - describe '#send_to_deadset' do + describe "#send_to_deadset" do subject(:send_to_deadset) { strategy.send_to_deadset } - context 'when deadset_kill?' do - before { allow(strategy).to receive(:deadset_kill?).and_return(true) } - - it 'calls deadset_kill' do - expect(strategy).to receive(:deadset_kill) + context "when deadset_kill?" do + before do + allow(strategy).to receive(:deadset_kill?).and_return(true) + allow(strategy).to receive(:deadset_kill) send_to_deadset end - end - context 'when not deadset_kill?' do - before { allow(strategy).to receive(:deadset_kill?).and_return(false) } + it "calls deadset_kill" do + expect(strategy).to have_received(:deadset_kill) + end + end - it 'calls push_to_deadset' do - expect(strategy).to receive(:push_to_deadset) + context "when not deadset_kill?" do + before do + allow(strategy).to receive(:deadset_kill?).and_return(false) + allow(strategy).to receive(:push_to_deadset) send_to_deadset end + + it "calls push_to_deadset" do + expect(strategy).to have_received(:push_to_deadset) + end end end - describe '#deadset_kill' do + describe "#deadset_kill" do subject(:deadset_kill) { strategy.deadset_kill } - context 'when kill_with_options?' do - before { allow(strategy).to receive(:kill_with_options?).and_return(true) } - - it 'calls kill_job_with_options' do - expect(strategy).to receive(:kill_job_with_options) + context "when kill_with_options?" do + before do + allow(strategy).to receive(:kill_with_options?).and_return(true) + allow(strategy).to receive(:kill_job_with_options) deadset_kill end - end - context 'when not kill_with_options?' do - before { allow(strategy).to receive(:kill_with_options?).and_return(false) } + it "calls kill_job_with_options" do + expect(strategy).to have_received(:kill_job_with_options) + end + end - it 'calls kill_job_without_options' do - expect(strategy).to receive(:kill_job_without_options) + context "when not kill_with_options?" do + before do + allow(strategy).to receive(:kill_with_options?).and_return(false) + allow(strategy).to receive(:kill_job_without_options) deadset_kill end + + it "calls kill_job_without_options" do + expect(strategy).to have_received(:kill_job_without_options) + end end end - describe '#kill_job_with_options' do + describe "#kill_job_with_options" do subject(:kill_job_with_options) { strategy.kill_job_with_options } - it 'calls deadset.kill with options hash', sidekiq_ver: '>= 5.1.0' do - expect(deadset).to receive(:kill).with(payload, notify_failure: false) + before do + allow(deadset).to receive(:kill) kill_job_with_options end + + it "calls deadset.kill with options hash", sidekiq_ver: ">= 5.1.0" do + expect(deadset).to have_received(:kill).with(payload, notify_failure: false) + end end - describe '#kill_job_without_options' do + describe "#kill_job_without_options" do subject(:kill_job_without_options) { strategy.kill_job_without_options } - it 'calls deadset.kill without options hash', sidekiq_ver: '>= 5.0.0 && < 5.1.0' do - expect(deadset).to receive(:kill).with(payload) + before do + allow(deadset).to receive(:kill) kill_job_without_options end + + it "calls deadset.kill without options hash", sidekiq_ver: ">= 5.0.0 && < 5.1.0" do + expect(deadset).to have_received(:kill).with(payload) + end end end diff --git a/spec/unit/sidekiq_unique_jobs/on_conflict/replace_spec.rb b/spec/unit/sidekiq_unique_jobs/on_conflict/replace_spec.rb index 2f0694a40..690b07ae8 100644 --- a/spec/unit/sidekiq_unique_jobs/on_conflict/replace_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/on_conflict/replace_spec.rb @@ -1,18 +1,17 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::OnConflict::Replace, redis: :redis do let(:strategy) { described_class.new(item) } - let(:unique_digest) { 'uniquejobs:56c68cab5038eb57959538866377560d' } - let(:block) { -> { p 'Hello' } } + let(:unique_digest) { "uniquejobs:56c68cab5038eb57959538866377560d" } + let(:block) { -> { p "Hello" } } let(:digest) { SidekiqUniqueJobs::Digests.all.first } let(:item) do - { 'unique_digest' => unique_digest, 'queue' => :customqueue } + { "unique_digest" => unique_digest, "queue" => :customqueue } end - describe '#call' do + describe "#call" do subject(:call) { strategy.call(&block) } before do @@ -21,53 +20,53 @@ allow(block).to receive(:call) end - context 'when job is retried' do - let(:jid) { 'abcdefab' } + context "when job is retried" do + let(:jid) { "abcdefab" } let(:job) { Sidekiq.dump_json(item) } let(:item) do { - 'class' => 'MyUniqueJob', - 'args' => [1, 2], - 'queue' => 'customqueue', - 'jid' => jid, - 'retry_count' => 2, - 'failed_at' => Time.now.to_f, - 'unique_digest' => unique_digest, + "class" => "MyUniqueJob", + "args" => [1, 2], + "queue" => "customqueue", + "jid" => jid, + "retry_count" => 2, + "failed_at" => Time.now.to_f, + "unique_digest" => unique_digest, } end before do Sidekiq.redis do |conn| - conn.zadd('retry', Time.now.to_f.to_s, job) + conn.zadd("retry", Time.now.to_f.to_s, job) end end - it 'removes the job from the retry set' do + it "removes the job from the retry set" do expect { call }.to change { retry_count }.from(1).to(0) expect(block).to have_received(:call) end end - context 'when job is scheduled' do + context "when job is scheduled" do let(:jid) { MyUniqueJob.perform_in(2000, 1, 1) } - it 'removes the job from the scheduled set' do + it "removes the job from the scheduled set" do expect { call }.to change { schedule_count }.from(1).to(0) expect(block).to have_received(:call) end end - context 'when job is enqueued' do + context "when job is enqueued" do let(:jid) { MyUniqueJob.perform_async(1, 1) } - it 'removes the job from the queue' do + it "removes the job from the queue" do expect { call }.to change { queue_count(:customqueue) }.from(1).to(0) expect(block).to have_received(:call) end end end - describe '#replace?' do + describe "#replace?" do subject { strategy.replace? } it { is_expected.to eq(true) } diff --git a/spec/unit/sidekiq_unique_jobs/on_conflict/reschedule_spec.rb b/spec/unit/sidekiq_unique_jobs/on_conflict/reschedule_spec.rb index ac0bc6b5c..6c5169fb6 100644 --- a/spec/unit/sidekiq_unique_jobs/on_conflict/reschedule_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/on_conflict/reschedule_spec.rb @@ -1,17 +1,16 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::OnConflict::Reschedule do let(:strategy) { described_class.new(item) } - let(:unique_digest) { 'uniquejobs:random-digest-value' } + let(:unique_digest) { "uniquejobs:random-digest-value" } let(:item) do - { 'class' => UniqueJobOnConflictReschedule, - 'unique_digest' => unique_digest, - 'args' => [1, 2] } + { "class" => UniqueJobOnConflictReschedule, + "unique_digest" => unique_digest, + "args" => [1, 2] } end - describe '#call' do + describe "#call" do let(:call) { strategy.call } it do @@ -19,7 +18,7 @@ end end - describe '#replace?' do + describe "#replace?" do subject { strategy.replace? } it { is_expected.to eq(false) } diff --git a/spec/unit/sidekiq_unique_jobs/on_conflict/strategy_spec.rb b/spec/unit/sidekiq_unique_jobs/on_conflict/strategy_spec.rb index f7f99dfac..4521d077f 100644 --- a/spec/unit/sidekiq_unique_jobs/on_conflict/strategy_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/on_conflict/strategy_spec.rb @@ -1,29 +1,28 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::OnConflict::Strategy, redis: :redis do let(:strategy) { described_class.new(item) } - let(:unique_digest) { 'uniquejobs:56c68cab5038eb57959538866377560d' } + let(:unique_digest) { "uniquejobs:56c68cab5038eb57959538866377560d" } let(:item) do - { 'unique_digest' => unique_digest, 'queue' => :customqueue } + { "unique_digest" => unique_digest, "queue" => :customqueue } end - describe '#replace?' do + describe "#replace?" do subject { strategy.replace? } it { is_expected.to eq(false) } end - describe '#call' do + describe "#call" do let(:call) { strategy.call } - it 'raises an error' do - expect { call }.to raise_error(NotImplementedError, 'needs to be implemented in child class') + it "raises an error" do + expect { call }.to raise_error(NotImplementedError, "needs to be implemented in child class") end end - describe '#replace?' do + describe "#replace?" do subject { strategy.replace? } it { is_expected.to eq(false) } diff --git a/spec/unit/sidekiq_unique_jobs/on_conflict_spec.rb b/spec/unit/sidekiq_unique_jobs/on_conflict_spec.rb index 354897774..2b1c41638 100644 --- a/spec/unit/sidekiq_unique_jobs/on_conflict_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/on_conflict_spec.rb @@ -1,9 +1,8 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::OnConflict do - describe '::STRAGEGIES' do + describe "::STRAGEGIES" do subject { described_class::STRATEGIES } let(:expected) do diff --git a/spec/unit/sidekiq_unique_jobs/options_with_fallback_spec.rb b/spec/unit/sidekiq_unique_jobs/options_with_fallback_spec.rb index 8dc5dc799..bc227a959 100644 --- a/spec/unit/sidekiq_unique_jobs/options_with_fallback_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/options_with_fallback_spec.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::OptionsWithFallback do class ClassWithOptions include SidekiqUniqueJobs::OptionsWithFallback @@ -16,24 +15,24 @@ def initialize(item, options, worker_class = nil) end let(:options_with_fallback) { ClassWithOptions.new(item, options, worker_class) } let(:options) { nil } - let(:worker_class) { 'UntilExecutedJob' } - let(:queue) { 'default' } - let(:jid) { 'maaaahjid' } + let(:worker_class) { "UntilExecutedJob" } + let(:queue) { "default" } + let(:jid) { "maaaahjid" } let(:unique) { :until_executed } let(:args) { [1] } let(:log_duplicate_payload) { false } let(:item) do { - 'jid' => jid, - 'queue' => queue, - 'class' => worker_class, - 'lock' => unique, - 'args' => args, - 'log_duplicate_payload' => log_duplicate_payload, + "jid" => jid, + "queue" => queue, + "class" => worker_class, + "lock" => unique, + "args" => args, + "log_duplicate_payload" => log_duplicate_payload, } end - describe '#unique_enabled?' do + describe "#unique_enabled?" do subject { options_with_fallback.unique_enabled? } let(:options) { {} } @@ -42,12 +41,12 @@ def initialize(item, options, worker_class = nil) it { is_expected.to eq(nil) } context 'when options["unique"] is present' do - let(:options) { { 'lock' => 'while_executing' } } - let(:item) { { 'lock' => 'until_executed' } } + let(:options) { { "lock" => "while_executing" } } + let(:item) { { "lock" => "until_executed" } } - it { is_expected.to eq('while_executing') } + it { is_expected.to eq("while_executing") } - context 'when SidekiqUniqueJobs.config.enabled = false' do + context "when SidekiqUniqueJobs.config.enabled = false" do before { SidekiqUniqueJobs.config.enabled = false } after { SidekiqUniqueJobs.config.enabled = true } @@ -57,11 +56,11 @@ def initialize(item, options, worker_class = nil) end context 'when item["unique"] is present' do - let(:item) { { 'lock' => 'until_executed' } } + let(:item) { { "lock" => "until_executed" } } - it { is_expected.to eq('until_executed') } + it { is_expected.to eq("until_executed") } - context 'when SidekiqUniqueJobs.config.enabled = false' do + context "when SidekiqUniqueJobs.config.enabled = false" do before { SidekiqUniqueJobs.config.enabled = false } after { SidekiqUniqueJobs.config.enabled = true } @@ -71,7 +70,7 @@ def initialize(item, options, worker_class = nil) end end - describe '#unique_disabled?' do + describe "#unique_disabled?" do subject { options_with_fallback.unique_disabled? } let(:options) { {} } @@ -80,25 +79,25 @@ def initialize(item, options, worker_class = nil) it { is_expected.to be_truthy } context 'when options["unique"] is present' do - let(:options) { { 'lock' => 'while_executing' } } - let(:item) { { 'lock' => 'until_executed' } } + let(:options) { { "lock" => "while_executing" } } + let(:item) { { "lock" => "until_executed" } } it { is_expected.to be_falsey } end context 'when item["unique"] is present' do let(:options) { {} } - let(:item) { { 'lock' => 'until_executed' } } + let(:item) { { "lock" => "until_executed" } } it { is_expected.to be_falsey } end end - describe '#log_duplicate_payload?' do + describe "#log_duplicate_payload?" do subject(:log_duplicate_payload?) { options_with_fallback.log_duplicate_payload? } context 'when options["log_duplicate_payload"] is true' do - let(:options) { { 'log_duplicate_payload' => true } } + let(:options) { { "log_duplicate_payload" => true } } it { is_expected.to eq(true) } end @@ -110,7 +109,7 @@ def initialize(item, options, worker_class = nil) end end - describe '#lock' do + describe "#lock" do subject(:lock) { options_with_fallback.lock } context 'when item["unique"] is present' do @@ -119,69 +118,69 @@ def initialize(item, options, worker_class = nil) it { is_expected.to be_a(SidekiqUniqueJobs::Lock::UntilExecuted) } context 'when options["unique"] is present' do - let(:options) { { 'lock' => :while_executing } } + let(:options) { { "lock" => :while_executing } } it { is_expected.to be_a(SidekiqUniqueJobs::Lock::WhileExecuting) } end end end - describe '#lock_class' do + describe "#lock_class" do subject(:lock_class) { options_with_fallback.lock_class } context 'when item["unique"] is present' do - let(:item) { { 'lock' => :until_executed } } + let(:item) { { "lock" => :until_executed } } it { is_expected.to eq(SidekiqUniqueJobs::Lock::UntilExecuted) } context 'when options["unique"] is present' do - let(:options) { { 'lock' => :while_executing } } + let(:options) { { "lock" => :while_executing } } it { is_expected.to eq(SidekiqUniqueJobs::Lock::WhileExecuting) } end end - context 'without matching class in LOCKS' do - let(:item) { { 'lock' => :until_unknown } } + context "without matching class in LOCKS" do + let(:item) { { "lock" => :until_unknown } } it do expect { lock_class } .to raise_error(SidekiqUniqueJobs::UnknownLock, - 'No implementation for `lock: :until_unknown`') + "No implementation for `lock: :until_unknown`") end end end - describe '#lock_type' do + describe "#lock_type" do subject { options_with_fallback.lock_type } context 'when options["unique"] is while_executing' do - let(:options) { { 'lock' => 'while_executing' } } - let(:item) { { 'lock' => 'until_executed' } } + let(:options) { { "lock" => "while_executing" } } + let(:item) { { "lock" => "until_executed" } } - it { is_expected.to eq('while_executing') } + it { is_expected.to eq("while_executing") } end context 'when item["unique"] is until_executed' do let(:options) { {} } - let(:item) { { 'lock' => 'until_executed' } } + let(:item) { { "lock" => "until_executed" } } - it { is_expected.to eq('until_executed') } + it { is_expected.to eq("until_executed") } end end - describe '#options' do + describe "#options" do subject(:class_options) { options_with_fallback.options } - context 'when worker_class respond_to get_sidekiq_options' do + context "when worker_class respond_to get_sidekiq_options" do let(:worker_class) { SimpleWorker } it { is_expected.to eq(SimpleWorker.get_sidekiq_options) } end - context 'when default_worker_options has been configured' do + context "when default_worker_options has been configured" do let(:worker_class) { PlainClass } - let(:default_worker_options) { { 'lock' => :while_executing } } + let(:default_worker_options) { { "lock" => :while_executing } } it do with_default_worker_options(default_worker_options) do diff --git a/spec/unit/sidekiq_unique_jobs/scripts_spec.rb b/spec/unit/sidekiq_unique_jobs/scripts_spec.rb index 530c5d344..fbbe302bb 100644 --- a/spec/unit/sidekiq_unique_jobs/scripts_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/scripts_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Scripts, redis: :redis do subject { SidekiqUniqueJobs::Scripts } @@ -10,18 +10,18 @@ it { is_expected.to respond_to(:script_source).with(1).arguments } it { is_expected.to respond_to(:script_path).with(1).arguments } - describe '.call' do + describe ".call" do subject(:call) { described_class.call(script_name, nil, options) } - let(:jid) { 'abcefab' } - let(:unique_key) { 'uniquejobs:abcefab' } + let(:jid) { "abcefab" } + let(:unique_key) { "uniquejobs:abcefab" } let(:max_lock_time) { 1 } let(:options) { { keys: [unique_key], argv: [jid, max_lock_time] } } - let(:scriptsha) { 'abcdefab' } + let(:scriptsha) { "abcdefab" } let(:script_name) { :acquire_lock } - let(:error_message) { 'Some interesting error' } + let(:error_message) { "Some interesting error" } - context 'when conn.evalsha raises Redis::CommandError' do + context "when conn.evalsha raises Redis::CommandError" do before do call_count = 0 allow(described_class).to receive(:execute_script).with(script_name, nil, options) do @@ -39,8 +39,8 @@ ) end - context 'when error message is No matching script' do - let(:error_message) { 'NOSCRIPT No matching script. Please use EVAL.' } + context "when error message is No matching script" do + let(:error_message) { "NOSCRIPT No matching script. Please use EVAL." } specify do expect(described_class::SCRIPT_SHAS).to receive(:delete).with(script_name) diff --git a/spec/unit/sidekiq_unique_jobs/server/middleware_spec.rb b/spec/unit/sidekiq_unique_jobs/server/middleware_spec.rb index ca9f3e6bf..91d869eca 100644 --- a/spec/unit/sidekiq_unique_jobs/server/middleware_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/server/middleware_spec.rb @@ -1,23 +1,21 @@ # frozen_string_literal: true -require 'spec_helper' - # rubocop:disable RSpec/InstanceVariable RSpec.describe SidekiqUniqueJobs::Server::Middleware do let(:middleware) { described_class.new } - describe '#call' do + describe "#call" do subject(:call) { middleware.call(worker_class, item, queue, &block) } let(:block) { -> { @inside_block_value = true } } let(:worker_class) { WhileExecutingJob } - let(:queue) { 'working' } + let(:queue) { "working" } let(:redis_pool) { nil } let(:args) { [1] } let(:item) do - { 'class' => worker_class, - 'queue' => queue, - 'args' => args } + { "class" => worker_class, + "queue" => queue, + "args" => args } end let(:lock) { instance_spy(SidekiqUniqueJobs::Lock::WhileExecuting) } @@ -27,22 +25,22 @@ allow(lock).to receive(:execute).and_yield end - context 'when unique is disabled' do + context "when unique is disabled" do before do allow(middleware).to receive(:unique_enabled?).and_return(false) end - it 'yields control' do + it "yields control" do expect { call }.to change { @inside_block_value }.to(true) end end - context 'when unique is enabled' do + context "when unique is enabled" do before do allow(middleware).to receive(:unique_enabled?).and_return(true) end - it 'yields control' do + it "yields control" do expect { call }.to change { @inside_block_value }.to(true) end end diff --git a/spec/unit/sidekiq_unique_jobs/sidekiq/api_spec.rb b/spec/unit/sidekiq_unique_jobs/sidekiq/api_spec.rb new file mode 100644 index 000000000..7183dfd70 --- /dev/null +++ b/spec/unit/sidekiq_unique_jobs/sidekiq/api_spec.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require "spec_helper" +RSpec.describe "Sidekiq::Api", redis: :redis do + let(:item) do + { "class" => "JustAWorker", + "queue" => "testqueue", + "args" => [foo: "bar"] } + end + + describe Sidekiq::SortedEntry::UniqueExtension do + it "deletes uniqueness lock on delete" do + expect(JustAWorker.perform_in(60 * 60 * 3, foo: "bar")).to be_truthy + expect(unique_keys).to match_array(%w[ + uniquejobs:863b7cb639bd71c828459b97788b2ada:EXISTS + uniquejobs:863b7cb639bd71c828459b97788b2ada:GRABBED + ]) + + Sidekiq::ScheduledSet.new.each(&:delete) + expect(keys("uniquejobs")).to match_array([]) + + expect(JustAWorker.perform_in(60 * 60 * 3, boo: "far")).to be_truthy + end + + it "deletes uniqueness lock on remove_job" do + expect(JustAWorker.perform_in(60 * 60 * 3, foo: "bar")).to be_truthy + expect(unique_keys).to match_array(%w[ + uniquejobs:863b7cb639bd71c828459b97788b2ada:EXISTS + uniquejobs:863b7cb639bd71c828459b97788b2ada:GRABBED + ]) + + Sidekiq::ScheduledSet.new.each do |entry| + entry.send(:remove_job) do |message| + item = Sidekiq.load_json(message) + expect(item).to match( + hash_including( + "args" => [{ "foo" => "bar" }], + "class" => "JustAWorker", + "jid" => kind_of(String), + "lock_expiration" => nil, + "lock_timeout" => 0, + "queue" => "testqueue", + "retry" => true, + "lock" => "until_executed", + "unique_args" => [{ "foo" => "bar" }], + "unique_digest" => "uniquejobs:863b7cb639bd71c828459b97788b2ada", + "unique_prefix" => "uniquejobs", + ), + ) + end + end + available_key = "uniquejobs:863b7cb639bd71c828459b97788b2ada:AVAILABLE" + expect(unique_keys).to match_array([available_key]) + expect(ttl(available_key)).to eq(5) + expect(JustAWorker.perform_in(60 * 60 * 3, boo: "far")).to be_truthy + end + end + + describe Sidekiq::Job::UniqueExtension do + it "deletes uniqueness lock on delete" do + jid = JustAWorker.perform_async(roo: "baf") + expect(keys).not_to match_array([]) + Sidekiq::Queue.new("testqueue").find_job(jid).delete + available_key = "uniquejobs:c2253601bbfe4f3ad300103026ed02f2:AVAILABLE" + expect(unique_keys).to match_array([available_key]) + expect(ttl(available_key)).to eq(5) + end + end + + describe Sidekiq::Queue::UniqueExtension do + it "deletes uniqueness locks on clear" do + JustAWorker.perform_async(oob: "far") + expect(keys).not_to match_array([]) + Sidekiq::Queue.new("testqueue").clear + available_key = "uniquejobs:ebd23329089b53ea1e93066a3365541f:AVAILABLE" + expect(unique_keys).to match_array([available_key]) + expect(ttl(available_key)).to eq(5) + end + end + + describe Sidekiq::JobSet::UniqueExtension do + it "deletes uniqueness locks on clear" do + JustAWorker.perform_in(60 * 60 * 3, roo: "fab") + expect(keys).not_to match_array([]) + Sidekiq::JobSet.new("schedule").clear + available_key = "uniquejobs:a88de37817cb5da99cf76408c7251a1d:AVAILABLE" + expect(unique_keys).to match_array([available_key]) + expect(ttl(available_key)).to eq(5) + end + end +end diff --git a/spec/unit/sidekiq_unique_jobs/sidekiq_unique_ext_spec.rb b/spec/unit/sidekiq_unique_jobs/sidekiq_unique_ext_spec.rb deleted file mode 100644 index 548fd6b18..000000000 --- a/spec/unit/sidekiq_unique_jobs/sidekiq_unique_ext_spec.rb +++ /dev/null @@ -1,92 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Sidekiq::Api', redis: :redis do - let(:item) do - { 'class' => 'JustAWorker', - 'queue' => 'testqueue', - 'args' => [foo: 'bar'] } - end - - describe Sidekiq::SortedEntry::UniqueExtension do - it 'deletes uniqueness lock on delete' do - expect(JustAWorker.perform_in(60 * 60 * 3, foo: 'bar')).to be_truthy - expect(unique_keys).to match_array(%w[ - uniquejobs:863b7cb639bd71c828459b97788b2ada:EXISTS - uniquejobs:863b7cb639bd71c828459b97788b2ada:GRABBED - ]) - - Sidekiq::ScheduledSet.new.each(&:delete) - expect(keys('uniquejobs')).to match_array([]) - - expect(JustAWorker.perform_in(60 * 60 * 3, boo: 'far')).to be_truthy - end - - it 'deletes uniqueness lock on remove_job' do - expect(JustAWorker.perform_in(60 * 60 * 3, foo: 'bar')).to be_truthy - expect(unique_keys).to match_array(%w[ - uniquejobs:863b7cb639bd71c828459b97788b2ada:EXISTS - uniquejobs:863b7cb639bd71c828459b97788b2ada:GRABBED - ]) - - Sidekiq::ScheduledSet.new.each do |entry| - entry.send(:remove_job) do |message| - item = Sidekiq.load_json(message) - expect(item).to match( - hash_including( - 'args' => [{ 'foo' => 'bar' }], - 'class' => 'JustAWorker', - 'jid' => kind_of(String), - 'lock_expiration' => nil, - 'lock_timeout' => 0, - 'queue' => 'testqueue', - 'retry' => true, - 'lock' => 'until_executed', - 'unique_args' => [{ 'foo' => 'bar' }], - 'unique_digest' => 'uniquejobs:863b7cb639bd71c828459b97788b2ada', - 'unique_prefix' => 'uniquejobs', - ), - ) - end - end - available_key = 'uniquejobs:863b7cb639bd71c828459b97788b2ada:AVAILABLE' - expect(unique_keys).to match_array([available_key]) - expect(ttl(available_key)).to eq(5) - expect(JustAWorker.perform_in(60 * 60 * 3, boo: 'far')).to be_truthy - end - end - - describe Sidekiq::Job::UniqueExtension do - it 'deletes uniqueness lock on delete' do - jid = JustAWorker.perform_async(roo: 'baf') - expect(keys).not_to match_array([]) - Sidekiq::Queue.new('testqueue').find_job(jid).delete - available_key = 'uniquejobs:c2253601bbfe4f3ad300103026ed02f2:AVAILABLE' - expect(unique_keys).to match_array([available_key]) - expect(ttl(available_key)).to eq(5) - end - end - - describe Sidekiq::Queue::UniqueExtension do - it 'deletes uniqueness locks on clear' do - JustAWorker.perform_async(oob: 'far') - expect(keys).not_to match_array([]) - Sidekiq::Queue.new('testqueue').clear - available_key = 'uniquejobs:ebd23329089b53ea1e93066a3365541f:AVAILABLE' - expect(unique_keys).to match_array([available_key]) - expect(ttl(available_key)).to eq(5) - end - end - - describe Sidekiq::JobSet::UniqueExtension do - it 'deletes uniqueness locks on clear' do - JustAWorker.perform_in(60 * 60 * 3, roo: 'fab') - expect(keys).not_to match_array([]) - Sidekiq::JobSet.new('schedule').clear - available_key = 'uniquejobs:a88de37817cb5da99cf76408c7251a1d:AVAILABLE' - expect(unique_keys).to match_array([available_key]) - expect(ttl(available_key)).to eq(5) - end - end -end diff --git a/spec/unit/sidekiq_unique_jobs/sidekiq_worker_methods_spec.rb b/spec/unit/sidekiq_unique_jobs/sidekiq_worker_methods_spec.rb index d58bdc34e..508c26953 100644 --- a/spec/unit/sidekiq_unique_jobs/sidekiq_worker_methods_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/sidekiq_worker_methods_spec.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::SidekiqWorkerMethods do class WorkerWithSidekiqMethods include SidekiqUniqueJobs::SidekiqWorkerMethods @@ -13,30 +12,30 @@ def initialize(worker_class) let(:worker) { WorkerWithSidekiqMethods.new(worker_class) } - describe '#worker_class_constantize' do + describe "#worker_class_constantize" do subject(:worker_class_constantize) { worker.worker_class_constantize } - context 'when worker_class is nil' do + context "when worker_class is nil" do let(:worker_class) { nil } it { is_expected.to eq(nil) } end - context 'when worker_class is MyUniqueJob' do + context "when worker_class is MyUniqueJob" do let(:worker_class) { MyUniqueJob } it { is_expected.to eq(MyUniqueJob) } end - context 'when worker_class is MyUniqueJob' do - let(:worker_class) { 'UntilExecutedJob' } + context "when worker_class is MyUniqueJob" do + let(:worker_class) { "UntilExecutedJob" } it { is_expected.to eq(UntilExecutedJob) } end - context 'when NameError is caught' do - let(:worker_class) { 'UnknownConstant' } - let(:error_message) { 'this class does not exist' } + context "when NameError is caught" do + let(:worker_class) { "UnknownConstant" } + let(:error_message) { "this class does not exist" } before do allow(Object).to receive(:const_get) @@ -44,14 +43,14 @@ def initialize(worker_class) .and_raise(NameError, error_message) end - it 'raises NameError' do + it "raises NameError" do expect { worker_class_constantize }.to raise_error(NameError, error_message) end - context 'when exception.message contains `uninitialized constant`' do - let(:error_message) { 'uninitialized constant' } + context "when exception.message contains `uninitialized constant`" do + let(:error_message) { "uninitialized constant" } - it { is_expected.to eq('UnknownConstant') } + it { is_expected.to eq("UnknownConstant") } end end end diff --git a/spec/unit/sidekiq_unique_jobs/timeout/calculator_spec.rb b/spec/unit/sidekiq_unique_jobs/timeout/calculator_spec.rb index cccd15b94..ef27bf6f3 100644 --- a/spec/unit/sidekiq_unique_jobs/timeout/calculator_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/timeout/calculator_spec.rb @@ -1,13 +1,12 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Timeout::Calculator do - let(:calculator) { described_class.new('class' => worker_class_name, 'at' => schedule_time) } - let(:worker_class_name) { 'MyUniqueJob' } + let(:calculator) { described_class.new("class" => worker_class_name, "at" => schedule_time) } + let(:worker_class_name) { "MyUniqueJob" } let(:schedule_time) { nil } - describe 'public api' do + describe "public api" do subject { calculator } it { is_expected.to respond_to(:time_until_scheduled) } @@ -18,14 +17,14 @@ it { is_expected.to respond_to(:default_worker_options) } end - describe '#time_until_scheduled' do + describe "#time_until_scheduled" do subject(:time_until_scheduled) { calculator.time_until_scheduled } - context 'when not scheduled' do + context "when not scheduled" do it { is_expected.to eq(0) } end - context 'when scheduled' do + context "when scheduled" do let(:schedule_time) { Time.now.utc.to_i + 24 * 60 * 60 } let(:now_in_utc) { Time.now.utc.to_i } @@ -37,10 +36,10 @@ end end - describe '#worker_class' do + describe "#worker_class" do subject(:worker_class) { calculator.worker_class } - let(:worker_class_name) { 'MyUniqueJob' } + let(:worker_class_name) { "MyUniqueJob" } it { is_expected.to eq(MyUniqueJob) } end diff --git a/spec/unit/sidekiq_unique_jobs/unique_args_spec.rb b/spec/unit/sidekiq_unique_jobs/unique_args_spec.rb index 49f36e73f..56084cbc8 100644 --- a/spec/unit/sidekiq_unique_jobs/unique_args_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/unique_args_spec.rb @@ -1,98 +1,105 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::UniqueArgs do let(:unique_args) { described_class.new(item) } let(:worker_class) { UntilExecutedJob } let(:class_name) { worker_class.to_s } - let(:queue) { 'myqueue' } + let(:queue) { "myqueue" } let(:args) { [[1, 2]] } let(:item) do { - 'class' => class_name, - 'queue' => queue, - 'args' => args, + "class" => class_name, + "queue" => queue, + "args" => args, } end - describe '#unique_digest' do + describe "#unique_digest" do subject(:unique_digest) { unique_args.unique_digest } - context 'when args are empty' do + context "when args are empty" do let(:another_unique_args) { described_class.new(item) } let(:worker_class) { WithoutArgumentJob } let(:args) { [] } - context 'with the same unique args' do - it 'equals to unique_digest for that item' do + context "with the same unique args" do + it "equals to unique_digest for that item" do expect(unique_digest).to eq(another_unique_args.unique_digest) end end end - shared_examples 'unique digest' do - context 'with another item' do + shared_examples "unique digest" do + context "with another item" do let(:another_unique_args) { described_class.new(another_item) } - context 'with the same unique args' do - let(:another_item) { item.merge('args' => [1, 2, 'type' => 'it']) } + context "with the same unique args" do + let(:another_item) { item.merge("args" => [1, 2, "type" => "it"]) } - it 'equals to unique_digest for that item' do + it "equals to unique_digest for that item" do expect(unique_digest).to eq(another_unique_args.unique_digest) end end - context 'with different unique args' do - let(:another_item) { item.merge('args' => [1, 3, 'type' => 'that']) } + context "with different unique args" do + let(:another_item) { item.merge("args" => [1, 3, "type" => "that"]) } - it 'differs from unique_digest for that item' do + it "differs from unique_digest for that item" do expect(unique_digest).not_to eq(another_unique_args.unique_digest) end end end end - context 'when unique_args is a proc' do + context "when unique_args is a proc" do let(:worker_class) { MyUniqueJobWithFilterProc } - let(:args) { [1, 2, 'type' => 'it'] } + let(:args) { [1, 2, "type" => "it"] } - it_behaves_like 'unique digest' + it_behaves_like "unique digest" end - context 'when unique_args is a symbol' do + context "when unique_args is a symbol" do let(:worker_class) { MyUniqueJobWithFilterMethod } - let(:args) { [1, 2, 'type' => 'it'] } + let(:args) { [1, 2, "type" => "it"] } - it_behaves_like 'unique digest' + it_behaves_like "unique digest" end end - describe '#digestable_hash' do + describe "#digestable_hash" do subject(:digestable_hash) { unique_args.digestable_hash } let(:expected_hash) do - { 'class' => 'UntilExecutedJob', 'queue' => 'myqueue', 'unique_args' => [[1, 2]] } + { "class" => "UntilExecutedJob", "queue" => "myqueue", "unique_args" => [[1, 2]] } end - it { is_expected.to eq(expected_hash) } + shared_examples "a digestable hash" do + it { is_expected.to eq(expected_hash) } + end + + it_behaves_like "a digestable hash" with_sidekiq_options_for(UntilExecutedJob, unique_args: :unique_args, unique_on_all_queues: true) do - let(:expected_hash) { { 'class' => 'UntilExecutedJob', 'unique_args' => [[1, 2]] } } - it { is_expected.to eq(expected_hash) } + let(:expected_hash) { { "class" => "UntilExecutedJob", "unique_args" => [[1, 2]] } } + + it_behaves_like "a digestable hash" end with_sidekiq_options_for(UntilExecutedJob, unique_across_workers: true) do - let(:expected_hash) { { 'queue' => 'myqueue', 'unique_args' => [[1, 2]] } } + let(:expected_hash) { { "queue" => "myqueue", "unique_args" => [[1, 2]] } } - it { is_expected.to eq(expected_hash) } + it_behaves_like "a digestable hash" end end - describe '#unique_args_enabled?' do + describe "#unique_args_enabled?" do subject(:unique_args_enabled?) { unique_args.unique_args_enabled? } - with_default_worker_options(unique: :until_executed, unique_args: ->(args) { args[1]['test'] }) do + shared_examples "" do + end + + with_default_worker_options(unique: :until_executed, unique_args: ->(args) { args[1]["test"] }) do with_sidekiq_options_for(UntilExecutedJob, unique_args: :unique_args) do it { is_expected.to eq(:unique_args) } end @@ -113,7 +120,7 @@ it { is_expected.to be_falsy } end - with_sidekiq_options_for('MissingWorker', unique_args: true) do + with_sidekiq_options_for("MissingWorker", unique_args: true) do it { is_expected.to be_falsy } end @@ -121,7 +128,7 @@ end end - describe '#unique_across_queues?' do + describe "#unique_across_queues?" do subject(:unique_across_queues?) { unique_args.unique_across_queues? } let(:worker_class) { UntilExecutedJob } @@ -137,7 +144,7 @@ end end - describe '#unique_across_workers?' do + describe "#unique_across_workers?" do subject(:unique_across_workers?) { unique_args.unique_across_workers? } it { is_expected.to eq(nil) } @@ -151,42 +158,42 @@ end end - describe '#filtered_args' do + describe "#filtered_args" do subject(:filtered_args) { unique_args.filtered_args(args) } - let(:args) { [1, 'test' => 'it'] } + let(:args) { [1, "test" => "it"] } before do allow(unique_args).to receive(:unique_args_method).and_return(unique_args_method) end - context 'when #unique_args_method is nil' do + context "when #unique_args_method is nil" do let(:unique_args_method) { nil } - it 'logs a debug message' do + it "logs a debug message" do allow(unique_args).to receive(:log_debug) filtered_args expect(unique_args) .to have_received(:log_debug) - .with('filtered_args arguments not filtered (using all arguments for uniqueness)') + .with("filtered_args arguments not filtered (using all arguments for uniqueness)") end it { is_expected.to eq(args) } end end - describe '#filter_by_proc' do + describe "#filter_by_proc" do subject(:filter_by_proc) { unique_args.filter_by_proc(args) } - let(:args) { [1, 'test' => 'it'] } + let(:args) { [1, "test" => "it"] } - context 'when #unique_args_method is a proc' do - let(:filter) { ->(args) { args[1]['test'] } } + context "when #unique_args_method is a proc" do + let(:filter) { ->(args) { args[1]["test"] } } before { allow(unique_args).to receive(:unique_args_method).and_return(filter) } - it { is_expected.to eq('it') } + it { is_expected.to eq("it") } end with_default_worker_options(unique_args: ->(args) { args.first }) do @@ -194,24 +201,24 @@ end end - describe '#filter_by_symbol' do + describe "#filter_by_symbol" do subject(:filter_by_symbol) { unique_args.filter_by_symbol(args) } - context 'when filter is a working symbol' do + context "when filter is a working symbol" do let(:worker_class) { UniqueJobWithFilterMethod } - let(:args) { ['name', 2, 'whatever' => nil, 'type' => 'test'] } + let(:args) { ["name", 2, "whatever" => nil, "type" => "test"] } let(:filtered_args) { %w[name test] } it { is_expected.to eq(filtered_args) } end - context 'when worker takes conditional parameters' do + context "when worker takes conditional parameters" do let(:worker_class) { UniqueJobWithoutUniqueArgsParameter } let(:args) { [1] } it { is_expected.to eq([1]) } - context 'when provided nil' do + context "when provided nil" do let(:args) { [] } it { is_expected.to eq([]) } @@ -220,21 +227,21 @@ context "when workers unique_args method doesn't take parameters" do let(:worker_class) { UniqueJobWithoutUniqueArgsParameter } - let(:args) { ['name', 2, 'whatever' => nil, 'type' => 'test'] } + let(:args) { ["name", 2, "whatever" => nil, "type" => "test"] } it { is_expected.to eq(args) } end - context 'when @worker_class does not respond_to unique_args_method' do + context "when @worker_class does not respond_to unique_args_method" do let(:worker_class) { UniqueJobWithNoUniqueArgsMethod } - let(:args) { ['name', 2, 'whatever' => nil, 'type' => 'test'] } + let(:args) { ["name", 2, "whatever" => nil, "type" => "test"] } it { is_expected.to eq(args) } end - context 'when workers unique_args method returns nil' do + context "when workers unique_args method returns nil" do let(:worker_class) { UniqueJobWithNilUniqueArgs } - let(:args) { ['name', 2, 'whatever' => nil, 'type' => 'test'] } + let(:args) { ["name", 2, "whatever" => nil, "type" => "test"] } it { is_expected.to eq(nil) } end diff --git a/spec/unit/sidekiq_unique_jobs/unlockable_spec.rb b/spec/unit/sidekiq_unique_jobs/unlockable_spec.rb index 3e20f1435..440f024fd 100644 --- a/spec/unit/sidekiq_unique_jobs/unlockable_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/unlockable_spec.rb @@ -1,21 +1,20 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Unlockable, redis: :redis do def item_with_digest SidekiqUniqueJobs::UniqueArgs.digest(item) item end let(:item) do - { 'class' => MyUniqueJob, - 'queue' => 'customqueue', - 'args' => [1, 2] } + { "class" => MyUniqueJob, + "queue" => "customqueue", + "args" => [1, 2] } end let(:unique_digest) { item_with_digest[SidekiqUniqueJobs::UNIQUE_DIGEST_KEY] } - describe '.unlock' do + describe ".unlock" do subject(:unlock) { described_class.unlock(item_with_digest) } let(:expected_keys) do @@ -34,7 +33,7 @@ def item_with_digest end end - describe '.delete' do + describe ".delete" do subject(:delete) { described_class.delete(item_with_digest) } specify do diff --git a/spec/unit/sidekiq_unique_jobs/util_spec.rb b/spec/unit/sidekiq_unique_jobs/util_spec.rb index f9c3e1692..8ba6da48e 100644 --- a/spec/unit/sidekiq_unique_jobs/util_spec.rb +++ b/spec/unit/sidekiq_unique_jobs/util_spec.rb @@ -1,20 +1,19 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs::Util, redis: :redis do let(:item_hash) do { - 'class' => 'MyUniqueJob', - 'args' => [[1, 2]], - 'at' => 1_492_341_850.358196, - 'retry' => true, - 'queue' => 'customqueue', - 'lock' => :until_executed, - 'lock_expiration' => 7200, - 'retry_count' => 10, - 'jid' => jid, - 'created_at' => 1_492_341_790.358217, + "class" => "MyUniqueJob", + "args" => [[1, 2]], + "at" => 1_492_341_850.358196, + "retry" => true, + "queue" => "customqueue", + "lock" => :until_executed, + "lock_expiration" => 7200, + "retry_count" => 10, + "jid" => jid, + "created_at" => 1_492_341_790.358217, } end @@ -24,8 +23,8 @@ my_item end - let(:unique_digest) { item['unique_digest'] } - let(:jid) { 'e3049b05b0bd9c809182bbe0' } + let(:unique_digest) { item["unique_digest"] } + let(:jid) { "e3049b05b0bd9c809182bbe0" } let(:lock) { SidekiqUniqueJobs::Locksmith.new(item) } let(:expected_keys) do %W[ @@ -34,29 +33,30 @@ ] end - shared_context 'with an old lock' do - before do - result = SidekiqUniqueJobs::Scripts.call( + shared_context "with an old lock" do + let!(:old_lock) do + SidekiqUniqueJobs::Scripts.call( :acquire_lock, nil, keys: [unique_digest], argv: [jid, 7200], ) - expect(result).to eq(1) - expect(described_class.keys).to include(unique_digest) end + + specify { expect(old_lock).to eq(1) } + specify { expect(described_class.keys).to include(unique_digest) } end - describe '.keys' do + describe ".keys" do subject(:keys) { described_class.keys } - context 'when old lock exists' do - include_context 'with an old lock' + context "when old lock exists" do + include_context "with an old lock" it { is_expected.to match_array([unique_digest]) } end - context 'when new lock exists' do + context "when new lock exists" do before do lock.lock(0) end @@ -65,22 +65,22 @@ end end - describe '.del' do + describe ".del" do subject(:del) { described_class.del(pattern, 100) } - context 'when an old lock exists' do - include_context 'with an old lock' + context "when an old lock exists" do + include_context "with an old lock" it { expect(described_class.keys).to match_array([unique_digest]) } - context 'when pattern is a wildcard' do + context "when pattern is a wildcard" do let(:pattern) { described_class::SCAN_PATTERN } it { is_expected.to eq(1) } it { expect { del }.to change(described_class, :keys).to([]) } end - context 'when pattern is a specific key' do + context "when pattern is a specific key" do let(:pattern) { unique_digest } it { is_expected.to eq(1) } @@ -88,7 +88,7 @@ end end - context 'when a new lock exists' do + context "when a new lock exists" do before do lock.lock(0) end @@ -97,14 +97,14 @@ it { expect(described_class.keys).to match_array(expected_keys) } - context 'when pattern is a wildcard' do + context "when pattern is a wildcard" do let(:pattern) { described_class::SCAN_PATTERN } it { is_expected.to eq(2) } it { expect { del }.to change(described_class, :keys).to([]) } end - context 'when pattern is a specific key' do + context "when pattern is a specific key" do let(:pattern) { unique_digest } it { is_expected.to eq(2) } @@ -113,27 +113,27 @@ end end - describe '.prefix' do + describe ".prefix" do subject(:prefix) { described_class.send(:prefix, key) } - let(:key) { 'key' } + let(:key) { "key" } - context 'when prefix is configured' do - before { allow(SidekiqUniqueJobs.config).to receive(:unique_prefix).and_return('test-uniqueness') } + context "when prefix is configured" do + before { allow(SidekiqUniqueJobs.config).to receive(:unique_prefix).and_return("test-uniqueness") } - it { is_expected.to eq('test-uniqueness:key') } + it { is_expected.to eq("test-uniqueness:key") } - context 'when key is already prefixed' do - let(:key) { 'test-uniqueness:key' } + context "when key is already prefixed" do + let(:key) { "test-uniqueness:key" } - it { is_expected.to eq('test-uniqueness:key') } + it { is_expected.to eq("test-uniqueness:key") } end end - context 'when .unique_prefix is nil?' do + context "when .unique_prefix is nil?" do before { allow(SidekiqUniqueJobs.config).to receive(:unique_prefix).and_return(nil) } - it { is_expected.to eq('key') } + it { is_expected.to eq("key") } end end end diff --git a/spec/unit/sidekiq_unique_jobs_spec.rb b/spec/unit/sidekiq_unique_jobs_spec.rb index db18914d9..3d80cf0ee 100644 --- a/spec/unit/sidekiq_unique_jobs_spec.rb +++ b/spec/unit/sidekiq_unique_jobs_spec.rb @@ -1,31 +1,30 @@ # frozen_string_literal: true -require 'spec_helper' - +require "spec_helper" RSpec.describe SidekiqUniqueJobs do - describe '.config' do + describe ".config" do subject(:config) { described_class.config } it { is_expected.to be_a(SidekiqUniqueJobs::Config) } its(:default_lock_timeout) { is_expected.to eq(0) } its(:enabled) { is_expected.to eq(true) } - its(:unique_prefix) { is_expected.to eq('uniquejobs') } + its(:unique_prefix) { is_expected.to eq("uniquejobs") } end - describe '.use_config' do - it 'changes configuration temporary' do - described_class.use_config(unique_prefix: 'bogus') do - expect(described_class.config.unique_prefix).to eq('bogus') + describe ".use_config" do + it "changes configuration temporary" do + described_class.use_config(unique_prefix: "bogus") do + expect(described_class.config.unique_prefix).to eq("bogus") end - expect(described_class.config.unique_prefix).to eq('uniquejobs') + expect(described_class.config.unique_prefix).to eq("uniquejobs") end end - describe '.configure' do - let(:options) { { unique_prefix: 'hi' } } + describe ".configure" do + let(:options) { { unique_prefix: "hi" } } - context 'when given a block' do + context "when given a block" do specify do expect { |block| described_class.configure(&block) }.to yield_control end @@ -38,15 +37,15 @@ end end - describe '.logger' do + describe ".logger" do subject { described_class.logger } - context 'without further configuration' do + context "without further configuration" do it { is_expected.to eq(Sidekiq.logger) } end - context 'when configured explicitly' do - let(:another_logger) { Logger.new('/dev/null') } + context "when configured explicitly" do + let(:another_logger) { Logger.new("/dev/null") } around do |exmpl| described_class.use_config(logger: another_logger) do @@ -58,11 +57,11 @@ end end - describe '.logger=' do + describe ".logger=" do let(:original_logger) { Sidekiq.logger } - let(:another_logger) { Logger.new('/dev/null') } + let(:another_logger) { Logger.new("/dev/null") } - it 'changes the SidekiqUniqueJobs.logger' do + it "changes the SidekiqUniqueJobs.logger" do expect { described_class.logger = another_logger } .to change(described_class, :logger) .from(original_logger) @@ -72,7 +71,7 @@ end end - describe '.redis_version' do + describe ".redis_version" do subject(:redis_version) { described_class.redis_version } it { is_expected.to be_a(String) } diff --git a/update_docs.sh b/update_docs.sh new file mode 100755 index 000000000..085a9957b --- /dev/null +++ b/update_docs.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +git checkout master +git fetch +stash_created=0 + +if [[ "$(git diff --stat)" != "" ]]; then + stash_created=1 + git stash push -u -a -m "Before updating docs" +fi; + +git pull --rebase + +rake yard + +git checkout gh-pages + +echo "Cleaning up current documentation" +find . ! -path '*/.git*' ! -path '*/doc*' ! -path '*/update_docs.sh*' ! -path '*/_config.yml*' ! -path '*/_index.html*' ! -path '.' | xargs rm -rf + +echo "Copying new documentation" +mv doc/* ./ + +echo "Sending new documentation to github" +git add --all +git commit -a -m 'Update documentation' +git push --force + +if [[ $stash_created == 1 ]]; then + git stash pop +fi; + +git checkout master