sidekiq-antidote 1.0.0.alpha.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 052bc50b4ce029ead4b2a4e6253625cf9a82a9c4071be61945e76336d9d13f18
4
- data.tar.gz: a12ac47db5f3edee4fba2e600b1da4029db87657a8bde540a7b3f2fb2c07911b
3
+ metadata.gz: 3692f76b40f4cf3cf7c8231c3a882e09ab5f81dec49cc3711b268602cd9bb0a3
4
+ data.tar.gz: 2845af94e4a35930c1cd775a075774ee72a70af2c3a498f802f2cc56f99edf07
5
5
  SHA512:
6
- metadata.gz: d9cf2a9e0db287b0b6c7d40a4fe99c7927dbb9aee9fdfd8efc06bdb81c91396f6b169271973746d2b543ac34673694c7894338d8c43d9f947f5f17659bafb4b8
7
- data.tar.gz: 57d9306f0b40cbccd67a1cf9f5d7260ddb59098cf1078fca7aca4ae88df58b669e38e2a2dd6059cb4d1c48ecdbf35e2eb56ff55bcdf957f4955dca33f0dee102
6
+ metadata.gz: 15c6e2fc733cae175d0e1d3b4b2f23ae666156c0b4386cf51287306d9601e3a09f4fccb2cac5adb6270f7e39e5937b99071e82804666a4fecc130ab2da020c04
7
+ data.tar.gz: a7307425321fd20db807a2e16419b6cad463288658cf78ce9063cacf828b83b84977075686882fb35c56e0c87cb8c060dc451bd6a788fe3b8af48f8d892ddc52
data/README.adoc CHANGED
@@ -1,5 +1,12 @@
1
1
  = Sidekiq::Antidote
2
2
 
3
+ :ci-url: https://github.com/ixti/sidekiq-antidote/actions/workflows/ci.yml?query=branch%3Amain
4
+ :ci-img: https://github.com/ixti/sidekiq-antidote/actions/workflows/ci.yml/badge.svg?branch=main
5
+ :codecov-url: https://codecov.io/gh/ixti/sidekiq-antidote/tree/main
6
+ :codecov-img: https://codecov.io/gh/ixti/sidekiq-antidote/graph/badge.svg?token=F5AAMPN35A
7
+
8
+ {ci-url}[image:{ci-img}[CI]]
9
+ {codecov-url}[image:{codecov-img}[codecov]]
3
10
 
4
11
  == Installation
5
12
 
@@ -20,10 +27,6 @@ require "sidekiq"
20
27
  require "sidekiq/antidote"
21
28
 
22
29
  Sidekiq::Antidote.configure do |config|
23
- # Set redis key prefix.
24
- # Default: nil
25
- config.key_prefix = "my-app:"
26
-
27
30
  # Set inhibitors cache refresh rate in seconds.
28
31
  # Default: 5.0
29
32
  config.refresh_rate = 10.0
@@ -50,6 +53,43 @@ require "sidekiq/antidote/web"
50
53
  ----
51
54
 
52
55
 
56
+ == Inhibitors
57
+
58
+ === Treatments
59
+
60
+ When adding antidote you must pick on of the treatments:
61
+
62
+ skip::
63
+ Skip the job (don't enqueue and/or perform)
64
+ kill::
65
+ Kill the job (send to the dead set instead of enqueueing and/or performing)
66
+
67
+
68
+ === Antidote Qualifiers
69
+
70
+ Qualifier is the job class pattern. It may match the job class or the job class
71
+ and method name (when used with ActionMailer delayed deliveries):
72
+
73
+ * `ExampleJob`
74
+ * `Namespaced::ExampleJob`
75
+ * `UserMailer#welcome`
76
+
77
+ You can also use pattern matching:
78
+
79
+ *::
80
+ Matches any number of alpha-numeric characters and underscores:
81
+ * `*Job` matches: `ExampleJob`, but not `Namespaced::ExampleJob`, or `UserMailer#welcome`
82
+ * `UserMailer#*` matches any method of `UserMailer`
83
+ **::
84
+ Matches any number of components:
85
+ * `**` mathes any job or mailer method
86
+ * `A::**::Job` matches `A::B::Job`, `A::B::C::D::CJob`, etc.
87
+ * `A**::Job` matches `A::Job`, `Abc::Job`, `A::B::Job`, etc.
88
+ {}::
89
+ Matches any of the given literal:
90
+ * `{A,B,C}Job` matches `AJob`, `BJob`, and `CJob`
91
+
92
+
53
93
  == Supported Ruby Versions
54
94
 
55
95
  This library aims to support and is tested against the following Ruby versions:
@@ -76,8 +116,6 @@ dropped.
76
116
 
77
117
  This library aims to support and work with following Sidekiq versions:
78
118
 
79
- * Sidekiq 7.0.x
80
- * Sidekiq 7.1.x
81
119
  * Sidekiq 7.2.x
82
120
 
83
121
 
@@ -3,53 +3,16 @@
3
3
  module Sidekiq
4
4
  module Antidote
5
5
  class Config
6
- REDIS_KEY = "sidekiq-antidote"
7
- private_constant :REDIS_KEY
8
-
9
6
  # Default refresh rate
10
7
  REFRESH_RATE = 5.0
11
8
 
12
- # @return [String?]
13
- attr_reader :key_prefix
14
-
15
9
  # @return [Float]
16
10
  attr_reader :refresh_rate
17
11
 
18
- # Fully qualified Redis key
19
- #
20
- # @example Without key prefix (default)
21
- # config.redis_key # => "sidekiq-antidote"
22
- #
23
- # @example With key prefix
24
- # config.key_prefix = "foobar:"
25
- # config.redis_key # => "foobar:sidekiq-antidote"
26
- #
27
- # @see #key_prefix
28
- # @return [String]
29
- attr_reader :redis_key
30
-
31
12
  def initialize
32
- @key_prefix = nil
33
- @redis_key = REDIS_KEY
34
13
  @refresh_rate = REFRESH_RATE
35
14
  end
36
15
 
37
- # Redis key prefix.
38
- #
39
- # @example
40
- # config.key_prefix = "foobar:"
41
- # config.redis_key # => "foobar:sidekiq-antidote"
42
- #
43
- # @see #redis_key
44
- # @param value [String, nil] String that should be prepended to redis key
45
- # @return [void]
46
- def key_prefix=(value)
47
- raise ArgumentError, "expected String, or nil; got #{value.class}" unless value.nil? || value.is_a?(String)
48
-
49
- @redis_key = [value, REDIS_KEY].compact.join.freeze
50
- @key_prefix = value&.then(&:-@) # Don't freeze original String value if it was unfrozen
51
- end
52
-
53
16
  # Inhibitors cache refresh rate in seconds.
54
17
  #
55
18
  # @param value [Float] refresh interval in seconds
@@ -4,6 +4,7 @@ require "concurrent"
4
4
 
5
5
  module Sidekiq
6
6
  module Antidote
7
+ # @api internal
7
8
  # Eventually consistent list of inhibitors. Used by middlewares to avoid
8
9
  # hitting Redis on every lookup.
9
10
  class Remedy
@@ -8,12 +8,7 @@ module Sidekiq
8
8
  class Repository
9
9
  include Enumerable
10
10
 
11
- # @param redis_key [#to_s]
12
- def initialize(redis_key)
13
- @redis_key = -redis_key.to_s
14
-
15
- freeze
16
- end
11
+ REDIS_KEY = "sidekiq-antidote"
17
12
 
18
13
  # @overload each
19
14
  # @return [Enumerator<Inhibitor>]
@@ -27,7 +22,7 @@ module Sidekiq
27
22
 
28
23
  broken_ids = []
29
24
 
30
- redis("HGETALL", @redis_key).each do |id, payload|
25
+ redis("HGETALL", REDIS_KEY).each do |id, payload|
31
26
  inhibitor = deserialize(id, payload)
32
27
  next yield inhibitor if inhibitor
33
28
 
@@ -50,7 +45,7 @@ module Sidekiq
50
45
  class_qualifier: class_qualifier
51
46
  )
52
47
 
53
- return inhibitor if redis("HSETNX", @redis_key, *serialize(inhibitor)).to_i.positive?
48
+ return inhibitor if redis("HSETNX", REDIS_KEY, *serialize(inhibitor)).to_i.positive?
54
49
  end
55
50
 
56
51
  raise "can't generate available ID"
@@ -59,7 +54,7 @@ module Sidekiq
59
54
  # @param ids [Array<String>]
60
55
  # @return [nil]
61
56
  def delete(*ids)
62
- redis("HDEL", @redis_key, *ids) unless ids.empty?
57
+ redis("HDEL", REDIS_KEY, *ids) unless ids.empty?
63
58
  nil
64
59
  end
65
60
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sidekiq
4
4
  module Antidote
5
- VERSION = "1.0.0.alpha.1"
5
+ VERSION = "1.0.0"
6
6
  end
7
7
  end
@@ -14,9 +14,10 @@ require_relative "./antidote/version"
14
14
  module Sidekiq
15
15
  module Antidote
16
16
  MUTEX = Mutex.new
17
+ private_constant :MUTEX
17
18
 
18
19
  @config = Config.new.freeze
19
- @repository = Repository.new(@config.redis_key)
20
+ @repository = Repository.new
20
21
  @remedy = Remedy.new(@config.refresh_rate, repository: @repository)
21
22
 
22
23
  class << self
@@ -32,10 +33,6 @@ module Sidekiq
32
33
  # @return (see Repository#delete)
33
34
  def_delegators :@repository, :delete
34
35
 
35
- # @!attribute [r] redis_key
36
- # @return [String]
37
- def_delegators :@config, :redis_key
38
-
39
36
  # @return [Array<Inhibitor>] Live list of inhibitors
40
37
  def inhibitors
41
38
  @repository.to_a
@@ -62,8 +59,7 @@ module Sidekiq
62
59
 
63
60
  yield config
64
61
 
65
- @config = config.freeze
66
- @repository = Repository.new(@config.redis_key)
62
+ @config = config.freeze
67
63
 
68
64
  self
69
65
  ensure
data/web/locales/en.yml CHANGED
@@ -1,8 +1,10 @@
1
1
  ---
2
2
  en:
3
3
  antidote.treatment: Treatment
4
- antidote.qualifier: Job Class Pattern
4
+ antidote.qualifier: Qualifier
5
5
  antidote.actions: Actions
6
6
  antidote.add: Add Inhibitor
7
- antidote.submit: Submit
7
+ antidote.add.submit: Submit
8
+ antidote.add.confirm: Are you sure you want to add the inhibitor?
8
9
  antidote.no_inhibitors: No inhibitors found
10
+ antidote.delete.confirm: Are you sure you want to delete inhibitor of ‹%{qualifier}› with ‹%{treatment}› treatment?
@@ -6,26 +6,51 @@
6
6
  <div class="alert alert-danger"><%= @error %></div>
7
7
  <% end %>
8
8
 
9
- <form id="antidote-inhibitor" action="<%=root_path %>antidote/add" method="post">
10
- <%= csrf_tag %>
11
- <div class="form-row">
12
- <div class="form-group col-md-2">
13
- <label for="antidote-inhibitor-treatment"><%= t("antidote.treatment") %></label>
14
- <select id="antidote-inhibitor-treatment" name="treatment" class="form-control">
15
- <% Sidekiq::Antidote::Inhibitor::TREATMENTS.each do |treatment| %>
16
- <option <%= "selected" if treatment == @treatment %>><%= treatment %></option>
9
+ <div class="col-sm-12">
10
+ <form id="antidote-inhibitor" class="form-horizontal" action="<%=root_path %>antidote/add" method="post">
11
+ <%= csrf_tag %>
12
+ <div class="form-group">
13
+ <label class="col-sm-2 control-label"><%= t("antidote.treatment") %></label>
14
+ <div class="radio col-sm-10">
15
+ <label>
16
+ <input id="antidote-inhibitor-treatment-skip" type="radio" name="treatment" value="skip" <%= "checked" if "skip" == @treatment %>>
17
+ skip <em class="text-muted">(don't enqueue and/or perform)</em>
18
+ </label>
19
+ </div>
20
+ <div class="radio col-sm-offset-2 col-sm-10">
21
+ <label>
22
+ <input id="antidote-inhibitor-treatment-kill" type="radio" name="treatment" value="kill" <%= "checked" if "kill" == @treatment %>>
23
+ kill <em class="text-muted">(send to the dead set instead of enqueueing and/or performing)</em>
24
+ </label>
25
+ </div>
26
+ </div>
27
+ <div class="form-group <%= "has-error" if @class_qualifier_error %>">
28
+ <label class="col-sm-2 control-label"><%= t("antidote.qualifier") %></label>
29
+ <div class="col-sm-10">
30
+ <input id="antidote-inhibitor-qualifier" type="text" class="form-control <%= "is-invalid" if @class_qualifier_error %>" name="class_qualifier" value="<%= @class_qualifier %>">
31
+ <% if @class_qualifier_error %>
32
+ <div id="antidote-inhibitor-qualifier-error" class="help-block">
33
+ <strong>ERROR:</strong> <%= @class_qualifier_error %>
34
+ </div>
17
35
  <% end %>
18
- </select>
36
+ <div class="help-block">
37
+ <strong>Examples:</strong>
38
+ <ul class="list-unstyled">
39
+ <li><kbd>ExampleJob</kbd> to match <var>ExampleJob</var> exactly</li>
40
+ <li><kbd>Namespaced::ExampleJob</kbd> to match <var>Namespaced::ExampleJob</var> exactly</li>
41
+ <li><kbd>UserMailer#welcome</kbd> to match <var>welcome</var> method of <var>UserMailer</var></li>
42
+ <li><kbd>*Job</kbd> to match <var>ExampleJob</var>, but not <var>Namespaced::ExampleJob</var></li>
43
+ <li><kbd>UserMailer#*</kbd> to match any method of <var>UserMailer</var></li>
44
+ <li><kbd>**Job</kbd> to match <var>ExampleJob</var>, <var>Namespaced::ExampleJob</var>, etc.</li>
45
+ <li><kbd>{A,B,C}Job</kbd> to match <var>AJob</var>, <var>BJob</var>, or <var>CJob</var></li>
46
+ </ul>
47
+ </div>
48
+ </div>
19
49
  </div>
20
- <div class="form-group col-md-10">
21
- <label for="antidote-inhibitor-class-qualifier"><%= t("antidote.qualifier") %></label>
22
- <input id="antidote-inhibitor-class-qualifier" type="text" class="form-control <%= "is-invalid" if @class_qualifier_error %>" name="class_qualifier" value="<%= @class_qualifier %>">
23
- <% if @class_qualifier_error %>
24
- <div id="antidote-inhibitor-class-qualifier-error" class="invalid-feedback"><%= @class_qualifier_error %></div>
25
- <% end %>
50
+ <div class="form-group">
51
+ <div class="radio col-sm-offset-2 col-sm-10">
52
+ <input class="btn btn-danger" type="submit" name="add" value="<%= t("antidote.add.submit") %>" data-confirm="<%= t("antidote.add.confirm") %>" />
53
+ </div>
26
54
  </div>
27
- </div>
28
- <div class="form-row text-right">
29
- <button id="antidote-inhibitor-submit" type="submit" class="btn"><%= t("antidote.submit") %></button>
30
- </div>
31
- </form>
55
+ </form>
56
+ </div>
@@ -23,7 +23,7 @@
23
23
  <td class="delete-confirm">
24
24
  <form action="<%=root_path %>antidote/<%= CGI.escape(inhibitor.id) %>/delete" method="post">
25
25
  <%= csrf_tag %>
26
- <input class="btn btn-danger" type="submit" name="delete" value="<%= t("Delete") %>" data-confirm="<%= t("AreYouSureDeleteQueue") %>" />
26
+ <input class="btn btn-danger" type="submit" name="delete" value="<%= t("Delete") %>" data-confirm="<%= t("antidote.delete.confirm", treatment: inhibitor.treatment, qualifier: inhibitor.class_qualifier) %>" />
27
27
  </form>
28
28
  </td>
29
29
  </tr>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-antidote
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexey Zapparov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-02 00:00:00.000000000 Z
11
+ date: 2023-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '7.0'
33
+ version: '7.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '7.0'
40
+ version: '7.2'
41
41
  description:
42
42
  email:
43
43
  - alexey@zapparov.com
@@ -66,9 +66,9 @@ licenses:
66
66
  - MIT
67
67
  metadata:
68
68
  homepage_uri: https://github.com/ixti/sidekiq-antidote
69
- source_code_uri: https://github.com/ixti/sidekiq-antidote/tree/v1.0.0.alpha.1
69
+ source_code_uri: https://github.com/ixti/sidekiq-antidote/tree/v1.0.0
70
70
  bug_tracker_uri: https://github.com/ixti/sidekiq-antidote/issues
71
- changelog_uri: https://github.com/ixti/sidekiq-antidote/blob/v1.0.0.alpha.1/CHANGES.md
71
+ changelog_uri: https://github.com/ixti/sidekiq-antidote/blob/v1.0.0/CHANGES.md
72
72
  rubygems_mfa_required: 'true'
73
73
  post_install_message:
74
74
  rdoc_options: []
@@ -81,9 +81,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
81
  version: '3.0'
82
82
  required_rubygems_version: !ruby/object:Gem::Requirement
83
83
  requirements:
84
- - - ">"
84
+ - - ">="
85
85
  - !ruby/object:Gem::Version
86
- version: 1.3.1
86
+ version: '0'
87
87
  requirements: []
88
88
  rubygems_version: 3.4.10
89
89
  signing_key: