karafka-core 2.5.1 → 2.5.2

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: '01592d62e014e631fffd3ae9477c8979e2df94ce3958b068d6ab5a79755e69aa'
4
- data.tar.gz: 65ce9e27480ec280e3b9f568ba09bf74e64298c7c14e796872a8f8bc40dd2541
3
+ metadata.gz: dcd7aa040c5e5025430de4755c6e3de2850f8e697a8222328a304f571d9bd1fc
4
+ data.tar.gz: b3498c28bf38256e7012a950a51f464d66a503c045227f1dde0e503b6d9550c3
5
5
  SHA512:
6
- metadata.gz: f785c2934587b78e42226b798bfa3023f4ed6985bb5e2048920fd5173df3e920f367c15a66e160d257c4d01c8265d7125ccfdcd3022ff1bc73685b6dcee0dde2
7
- data.tar.gz: 7f38ce66ec1e49c993e207e1b3967637d99f04c6e62b1c852fb5788fb4348ff6942a8c59c2d23d4735e982db2a4a820773653f292edc2ce022aef61b2cf6abb1
6
+ metadata.gz: 350399becfcf8a702a9c106cb6f6310dc57255549fbe54cd7bbadae4e1c2c1e13efc53b9d60972c20c2a057775483461f73f60dc2839da964db39de47b7f608d
7
+ data.tar.gz: 4b94de1f08121280d3321dad105487e7b3e3ddaefe2ba2d4a3dd67a5c2fe3b23cb5588fa707d8ad513346c860749f9389431751b26c1688b19104a585bda4de6
@@ -1,4 +1,4 @@
1
- name: ci
1
+ name: CI
2
2
 
3
3
  concurrency:
4
4
  group: ${{ github.workflow }}-${{ github.ref }}
@@ -40,7 +40,7 @@ jobs:
40
40
  run: "[ -e $APT_DEPS ] || sudo apt-get install -y --no-install-recommends $APT_DEPS"
41
41
 
42
42
  - name: Set up Ruby
43
- uses: ruby/setup-ruby@1a0ff446f5856bdfec298b61a09727c860d9d480 # v1.240.0
43
+ uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
44
44
  with:
45
45
  ruby-version: ${{matrix.ruby}}
46
46
  bundler: 'latest'
@@ -71,7 +71,7 @@ jobs:
71
71
  with:
72
72
  fetch-depth: 0
73
73
  - name: Set up Ruby
74
- uses: ruby/setup-ruby@1a0ff446f5856bdfec298b61a09727c860d9d480 # v1.240.0
74
+ uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
75
75
  with:
76
76
  ruby-version: 3.4
77
77
  - name: Install latest bundler
@@ -24,7 +24,7 @@ jobs:
24
24
  fetch-depth: 0
25
25
 
26
26
  - name: Set up Ruby
27
- uses: ruby/setup-ruby@1a0ff446f5856bdfec298b61a09727c860d9d480 # v1.240.0
27
+ uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
28
28
  with:
29
29
  bundler-cache: false
30
30
 
@@ -32,5 +32,4 @@ jobs:
32
32
  run: |
33
33
  bundle install --jobs 4 --retry 3
34
34
 
35
- # Release
36
- - uses: rubygems/release-gem@9e85cb11501bebc2ae661c1500176316d3987059 # v1
35
+ - uses: rubygems/release-gem@a25424ba2ba8b387abc8ef40807c2c85b96cbe32 # v1.1.1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Karafka Core Changelog
2
2
 
3
+ ## 2.5.2 (2025-06-11)
4
+ - [Enhancement] Support `#unsubscribe`.
5
+ - [Enhancement] Allow for providing a root scope path for error keys.
6
+ - [Fix] Fix a bug where on no errors the result would be an array instead of a hash.
7
+ - [Fix] Fix spec hanging when Kafka cluster on 9092 is running.
8
+
3
9
  ## 2.5.1 (2025-05-23)
4
10
  - [Change] Move to trusted-publishers and remove signing since no longer needed.
5
11
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka-core (2.5.1)
4
+ karafka-core (2.5.2)
5
5
  karafka-rdkafka (>= 0.19.2, < 0.21.0)
6
6
  logger (>= 1.6.0)
7
7
 
@@ -22,26 +22,26 @@ GEM
22
22
  ffi (1.17.2-x86_64-darwin)
23
23
  ffi (1.17.2-x86_64-linux-gnu)
24
24
  ffi (1.17.2-x86_64-linux-musl)
25
- karafka-rdkafka (0.19.2)
25
+ karafka-rdkafka (0.19.5)
26
26
  ffi (~> 1.15)
27
27
  mini_portile2 (~> 2.6)
28
28
  rake (> 12)
29
29
  logger (1.7.0)
30
30
  mini_portile2 (2.8.9)
31
- rake (13.2.1)
32
- rspec (3.13.0)
31
+ rake (13.3.0)
32
+ rspec (3.13.1)
33
33
  rspec-core (~> 3.13.0)
34
34
  rspec-expectations (~> 3.13.0)
35
35
  rspec-mocks (~> 3.13.0)
36
- rspec-core (3.13.3)
36
+ rspec-core (3.13.4)
37
37
  rspec-support (~> 3.13.0)
38
- rspec-expectations (3.13.4)
38
+ rspec-expectations (3.13.5)
39
39
  diff-lcs (>= 1.2.0, < 2.0)
40
40
  rspec-support (~> 3.13.0)
41
- rspec-mocks (3.13.4)
41
+ rspec-mocks (3.13.5)
42
42
  diff-lcs (>= 1.2.0, < 2.0)
43
43
  rspec-support (~> 3.13.0)
44
- rspec-support (3.13.3)
44
+ rspec-support (3.13.4)
45
45
  simplecov (0.22.0)
46
46
  docile (~> 1.1)
47
47
  simplecov-html (~> 0.11)
@@ -78,18 +78,20 @@ module Karafka
78
78
  # Runs the validation
79
79
  #
80
80
  # @param data [Hash] hash with data we want to validate
81
+ # @param scope [Array<String>] scope of this contract (if any) or empty array if no parent
82
+ # scope is needed if contract starts from root
81
83
  # @return [Result] validaton result
82
- def call(data)
84
+ def call(data, scope: [])
83
85
  errors = []
84
86
 
85
87
  self.class.rules.each do |rule|
86
88
  case rule.type
87
89
  when :required
88
- validate_required(data, rule, errors)
90
+ validate_required(data, rule, errors, scope)
89
91
  when :optional
90
- validate_optional(data, rule, errors)
92
+ validate_optional(data, rule, errors, scope)
91
93
  when :virtual
92
- validate_virtual(data, rule, errors)
94
+ validate_virtual(data, rule, errors, scope)
93
95
  end
94
96
  end
95
97
 
@@ -98,11 +100,13 @@ module Karafka
98
100
 
99
101
  # @param data [Hash] data for validation
100
102
  # @param error_class [Class] error class that should be used when validation fails
103
+ # @param scope [Array<String>] scope of this contract (if any) or empty array if no parent
104
+ # scope is needed if contract starts from root
101
105
  # @return [Boolean] true
102
106
  # @raise [StandardError] any error provided in the error_class that inherits from the
103
107
  # standard error
104
- def validate!(data, error_class)
105
- result = call(data)
108
+ def validate!(data, error_class, scope: [])
109
+ result = call(data, scope: scope)
106
110
 
107
111
  return true if result.success?
108
112
 
@@ -117,19 +121,20 @@ module Karafka
117
121
  # @param data [Hash] input hash
118
122
  # @param rule [Rule] validation rule
119
123
  # @param errors [Array] array with errors from previous rules (if any)
120
- def validate_required(data, rule, errors)
124
+ # @param scope [Array<String>]
125
+ def validate_required(data, rule, errors, scope)
121
126
  for_checking = dig(data, rule.path)
122
127
 
123
128
  # We need to compare `DIG_MISS` against stuff because of the ownership of the `#==`
124
129
  # method
125
130
  if DIG_MISS == for_checking
126
- errors << [rule.path, :missing]
131
+ errors << [scope + rule.path, :missing]
127
132
  else
128
133
  result = rule.validator.call(for_checking, data, errors, self)
129
134
 
130
135
  return if result == true
131
136
 
132
- errors << [rule.path, result || :format]
137
+ errors << [scope + rule.path, result || :format]
133
138
  end
134
139
  end
135
140
 
@@ -139,7 +144,8 @@ module Karafka
139
144
  # @param data [Hash] input hash
140
145
  # @param rule [Rule] validation rule
141
146
  # @param errors [Array] array with errors from previous rules (if any)
142
- def validate_optional(data, rule, errors)
147
+ # @param scope [Array<String>]
148
+ def validate_optional(data, rule, errors, scope)
143
149
  for_checking = dig(data, rule.path)
144
150
 
145
151
  return if DIG_MISS == for_checking
@@ -148,7 +154,7 @@ module Karafka
148
154
 
149
155
  return if result == true
150
156
 
151
- errors << [rule.path, result || :format]
157
+ errors << [scope + rule.path, result || :format]
152
158
  end
153
159
 
154
160
  # Runs validation for rules on virtual fields (aggregates, etc) and adds errors (if any) to
@@ -157,11 +163,18 @@ module Karafka
157
163
  # @param data [Hash] input hash
158
164
  # @param rule [Rule] validation rule
159
165
  # @param errors [Array] array with errors from previous rules (if any)
160
- def validate_virtual(data, rule, errors)
166
+ # @param scope [Array<String>]
167
+ def validate_virtual(data, rule, errors, scope)
161
168
  result = rule.validator.call(data, errors, self)
162
169
 
163
170
  return if result == true
164
171
 
172
+ if result
173
+ result.each do |sub_result|
174
+ sub_result[0] = scope + sub_result[0]
175
+ end
176
+ end
177
+
165
178
  errors.push(*result)
166
179
  end
167
180
 
@@ -14,7 +14,7 @@ module Karafka
14
14
  def initialize(errors, contract)
15
15
  # Short track to skip object allocation for the happy path
16
16
  if errors.empty?
17
- @errors = errors
17
+ @errors = {}
18
18
  return
19
19
  end
20
20
 
@@ -41,7 +41,8 @@ module Karafka
41
41
 
42
42
  private
43
43
 
44
- # Builds message based on the error messages
44
+ # Builds message based on the error messages and scope
45
+ #
45
46
  # @param contract [Object] contract for which we build the result
46
47
  # @param scope [Symbol] path to the key that has an error
47
48
  # @param error_key [Symbol] error key for yaml errors lookup
@@ -49,6 +50,25 @@ module Karafka
49
50
  def build_message(contract, scope, error_key)
50
51
  messages = contract.class.config.error_messages
51
52
 
53
+ # Split scope into parts for progressive checking
54
+ scope_parts = scope.to_s.split('.')
55
+
56
+ # Try full scope first, then progressively remove from beginning
57
+ # This allows us to have full path scoped errors but can also be used as a fallback,
58
+ # when scopes are dynamic. For example 'consumer_group_name.topic_name.name_format'
59
+ (0..scope_parts.length).each do |i|
60
+ current_scope_parts = scope_parts[i..]
61
+
62
+ key = if current_scope_parts.empty?
63
+ error_key.to_s
64
+ else
65
+ "#{current_scope_parts.join('.')}_#{error_key}"
66
+ end
67
+
68
+ return messages[key] if messages.key?(key)
69
+ end
70
+
71
+ # If nothing found, raise the original error
52
72
  messages.fetch(error_key.to_s) do
53
73
  messages.fetch("#{scope}_#{error_key}")
54
74
  end
@@ -42,6 +42,14 @@ module Karafka
42
42
  @notifications_bus.subscribe(*args, &block)
43
43
  end
44
44
 
45
+ # Allows for removal of whatever was subscribed
46
+ #
47
+ # @param listener_or_block [Object] object that is subscribed whether this is a listener
48
+ # instance or a block.
49
+ def unsubscribe(listener_or_block)
50
+ @notifications_bus.unsubscribe(listener_or_block)
51
+ end
52
+
45
53
  # @return [Hash<String, Array>] hash where keys are events and values are arrays with
46
54
  # listeners subscribed to particular events. Since different events may have different
47
55
  # listeners, this is returned that way.
@@ -89,6 +89,21 @@ module Karafka
89
89
  end
90
90
  end
91
91
 
92
+ # Allows for unsubscription from events
93
+ # This method will remove the listener/block from all events where it's currently subscribed.
94
+ #
95
+ # @param listener_or_block [Object] listener object or block to remove from all events
96
+ #
97
+ # @example Unsubscribe using listener (removes from all events where it's subscribed)
98
+ # unsubscribe(my_listener)
99
+ def unsubscribe(listener_or_block)
100
+ @mutex.synchronize do
101
+ @listeners.each_value do |event_listeners|
102
+ event_listeners.delete(listener_or_block)
103
+ end
104
+ end
105
+ end
106
+
92
107
  # Allows for code instrumentation
93
108
  # Runs the provided code and sends the instrumentation details to all registered listeners
94
109
  #
@@ -4,6 +4,6 @@ module Karafka
4
4
  module Core
5
5
  # Current Karafka::Core version
6
6
  # We follow the versioning schema of given Karafka version
7
- VERSION = '2.5.1'
7
+ VERSION = '2.5.2'
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: karafka-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.1
4
+ version: 2.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld