karafka 2.0.30 → 2.0.31

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2c983b3fbf07db3e91f3c051a8b4de4b2d88619877fbf66a4e434e38bf67c96b
4
- data.tar.gz: babb3c513e6bb3fd0610363e3bbd9e7fcf07b1820f02fdd80ccacc8a109aab08
3
+ metadata.gz: a4c598dcc6414c2a24f50452d5379c2a0aa26d7d1c7fd8d1b07f2af19a6e8125
4
+ data.tar.gz: 184a8b1e7bb1f62672f90904ce6c3fd5e2da5f1868bcb2a971a1e7872e8c3252
5
5
  SHA512:
6
- metadata.gz: ea000c13a834ffba97c1837fa1f19dabbf78dbe8958354a8200bb5d2c0940852343521e6740113e07890f97a7e6edd108d8595a66688c4c14dbf313e86ec715f
7
- data.tar.gz: 81ae980ef7950c6cae7d1bea2751d1826e5bbf4c1384be4736af895977fb7ff38f70c24a9b7b248cb18744e042ffb0ba0dc154171c29dcc73262733d87c31ea1
6
+ metadata.gz: a9d382efa4846f4419d86d1fa2742f663e2c255b203612b6810ab5bc44aafc8c9a1c6c299330889c0cc54cb952235ddbb8d45a3c2ed30c7132b8522fc46ef8d1
7
+ data.tar.gz: 5a5907e0e7b958a6277785ef4254ac5d8cf7f563e371fdf3fe7705719164362858b46efae62dda6c7a1f02646ffd57d05437fde496ebf2b7e36bdcb8ac57865d
checksums.yaml.gz.sig CHANGED
Binary file
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.2.0
1
+ 3.2.1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Karafka framework changelog
2
2
 
3
+ ## 2.0.31 (2022-02-12)
4
+ - [Feature] Allow for adding partitions via `Admin#create_partitions` API.
5
+ - [Fix] Do not ignore admin errors upon invalid configuration (#1254)
6
+ - [Fix] Topic name validation (#1300) - CandyFet
7
+ - [Improvement] Increase the `max_wait_timeout` on admin operations to five minutes to make sure no timeout on heavily loaded clusters.
8
+ - [Maintenance] Require `karafka-core` >= `2.0.11` and switch to shared RSpec locator.
9
+ - [Maintenance] Require `karafka-rdkafka` >= `0.12.1`
10
+
3
11
  ## 2.0.30 (2022-01-31)
4
12
  - [Improvement] Alias `--consumer-groups` with `--include-consumer-groups`
5
13
  - [Improvement] Alias `--subscription-groups` with `--include-subscription-groups`
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka (2.0.30)
5
- karafka-core (>= 2.0.9, < 3.0.0)
4
+ karafka (2.0.31)
5
+ karafka-core (>= 2.0.11, < 3.0.0)
6
6
  thor (>= 0.20)
7
7
  waterdrop (>= 2.4.10, < 3.0.0)
8
8
  zeitwerk (~> 2.3)
@@ -29,10 +29,10 @@ GEM
29
29
  activesupport (>= 5.0)
30
30
  i18n (1.12.0)
31
31
  concurrent-ruby (~> 1.0)
32
- karafka-core (2.0.9)
32
+ karafka-core (2.0.11)
33
33
  concurrent-ruby (>= 1.1)
34
- karafka-rdkafka (>= 0.12)
35
- karafka-rdkafka (0.12.0)
34
+ karafka-rdkafka (>= 0.12.1)
35
+ karafka-rdkafka (0.12.1)
36
36
  ffi (~> 1.15)
37
37
  mini_portile2 (~> 2.6)
38
38
  rake (> 12)
@@ -43,7 +43,7 @@ GEM
43
43
  rspec-core (~> 3.12.0)
44
44
  rspec-expectations (~> 3.12.0)
45
45
  rspec-mocks (~> 3.12.0)
46
- rspec-core (3.12.0)
46
+ rspec-core (3.12.1)
47
47
  rspec-support (~> 3.12.0)
48
48
  rspec-expectations (3.12.2)
49
49
  diff-lcs (>= 1.2.0, < 2.0)
@@ -79,4 +79,4 @@ DEPENDENCIES
79
79
  simplecov
80
80
 
81
81
  BUNDLED WITH
82
- 2.4.5
82
+ 2.4.6
@@ -45,10 +45,12 @@ en:
45
45
  dead_letter_queue.topic_format: 'needs to be a string with a Kafka accepted format'
46
46
  dead_letter_queue.active_format: needs to be either true or false
47
47
  active_format: needs to be either true or false
48
+ inconsistent_namespacing: needs to be consistent namespacing style
48
49
 
49
50
  consumer_group:
50
51
  missing: needs to be present
51
52
  topics_names_not_unique: all topic names within a single consumer group must be unique
53
+ topics_namespaced_names_not_unique: all topic names within a single consumer group must be unique considering namespacing styles
52
54
  id_format: 'needs to be a string with a Kafka accepted format'
53
55
  topics_format: needs to be a non-empty array
54
56
 
data/karafka.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  without having to focus on things that are not your business domain.
22
22
  DESC
23
23
 
24
- spec.add_dependency 'karafka-core', '>= 2.0.9', '< 3.0.0'
24
+ spec.add_dependency 'karafka-core', '>= 2.0.11', '< 3.0.0'
25
25
  spec.add_dependency 'thor', '>= 0.20'
26
26
  spec.add_dependency 'waterdrop', '>= 2.4.10', '< 3.0.0'
27
27
  spec.add_dependency 'zeitwerk', '~> 2.3'
data/lib/karafka/admin.rb CHANGED
@@ -14,6 +14,13 @@ module Karafka
14
14
  # do not have in the routing
15
15
  Topic = Struct.new(:name, :deserializer)
16
16
 
17
+ # We wait only for this amount of time before raising error as we intercept this error and
18
+ # retry after checking that the operation was finished or failed using external factor.
19
+ MAX_WAIT_TIMEOUT = 1
20
+
21
+ # How many times should be try. 1 x 60 => 60 seconds wait in total
22
+ MAX_ATTEMPTS = 60
23
+
17
24
  # Defaults for config
18
25
  CONFIG_DEFAULTS = {
19
26
  'group.id': 'karafka_admin',
@@ -22,7 +29,7 @@ module Karafka
22
29
  'statistics.interval.ms': 0
23
30
  }.freeze
24
31
 
25
- private_constant :Topic, :CONFIG_DEFAULTS
32
+ private_constant :Topic, :CONFIG_DEFAULTS, :MAX_WAIT_TIMEOUT, :MAX_ATTEMPTS
26
33
 
27
34
  class << self
28
35
  # Allows us to read messages from the topic
@@ -86,9 +93,12 @@ module Karafka
86
93
  # https://kafka.apache.org/documentation/#topicconfigs
87
94
  def create_topic(name, partitions, replication_factor, topic_config = {})
88
95
  with_admin do |admin|
89
- admin.create_topic(name, partitions, replication_factor, topic_config)
96
+ handler = admin.create_topic(name, partitions, replication_factor, topic_config)
90
97
 
91
- sleep(0.2) until topics_names.include?(name)
98
+ with_re_wait(
99
+ -> { handler.wait(max_wait_timeout: MAX_WAIT_TIMEOUT) },
100
+ -> { topics_names.include?(name) }
101
+ )
92
102
  end
93
103
  end
94
104
 
@@ -97,9 +107,27 @@ module Karafka
97
107
  # @param name [String] topic name
98
108
  def delete_topic(name)
99
109
  with_admin do |admin|
100
- admin.delete_topic(name)
110
+ handler = admin.delete_topic(name)
101
111
 
102
- sleep(0.2) while topics_names.include?(name)
112
+ with_re_wait(
113
+ -> { handler.wait(max_wait_timeout: MAX_WAIT_TIMEOUT) },
114
+ -> { !topics_names.include?(name) }
115
+ )
116
+ end
117
+ end
118
+
119
+ # Creates more partitions for a given topic
120
+ #
121
+ # @param name [String] topic name
122
+ # @param partitions [Integer] total number of partitions we expect to end up with
123
+ def create_partitions(name, partitions)
124
+ with_admin do |admin|
125
+ handler = admin.create_partitions(name, partitions)
126
+
127
+ with_re_wait(
128
+ -> { handler.wait(max_wait_timeout: MAX_WAIT_TIMEOUT) },
129
+ -> { topic(name).fetch(:partition_count) >= partitions }
130
+ )
103
131
  end
104
132
  end
105
133
 
@@ -117,6 +145,13 @@ module Karafka
117
145
  cluster_info.topics.map { |topic| topic.fetch(:topic_name) }
118
146
  end
119
147
 
148
+ # Finds details about given topic
149
+ # @param name [String] topic name
150
+ # @return [Hash] topic details
151
+ def topic(name)
152
+ cluster_info.topics.find { |topic| topic[:topic_name] == name }
153
+ end
154
+
120
155
  # Creates admin instance and yields it. After usage it closes the admin instance
121
156
  def with_admin
122
157
  admin = config(:producer).admin
@@ -133,6 +168,28 @@ module Karafka
133
168
  consumer&.close
134
169
  end
135
170
 
171
+ # There are some cases where rdkafka admin operations finish successfully but without the
172
+ # callback being triggered to materialize the post-promise object. Until this is fixed we
173
+ # can figure out, that operation we wanted to do finished successfully by checking that the
174
+ # effect of the command (new topic, more partitions, etc) is handled. Exactly for that we
175
+ # use the breaker. It we get a timeout, we can check that what we wanted to achieve has
176
+ # happened via the breaker check, hence we do not need to wait any longer.
177
+ #
178
+ # @param handler [Proc] the wait handler operation
179
+ # @param breaker [Proc] extra condition upon timeout that indicates things were finished ok
180
+ def with_re_wait(handler, breaker)
181
+ attempt ||= 0
182
+ attempt += 1
183
+
184
+ handler.call
185
+ rescue Rdkafka::AbstractHandle::WaitTimeoutError
186
+ return if breaker.call
187
+
188
+ retry if attempt <= MAX_ATTEMPTS
189
+
190
+ raise
191
+ end
192
+
136
193
  # @param type [Symbol] type of config we want
137
194
  # @return [::Rdkafka::Config] rdkafka config
138
195
  def config(type)
@@ -24,6 +24,32 @@ module Karafka
24
24
 
25
25
  [[%i[topics], :names_not_unique]]
26
26
  end
27
+
28
+ virtual do |data, errors|
29
+ next unless errors.empty?
30
+
31
+ names = data.fetch(:topics).map { |topic| topic[:name] }
32
+ names_hash = names.each_with_object({}) { |n, h| h[n] = true }
33
+ error_occured = false
34
+ names.each do |n|
35
+ # Skip topic names that are not namespaced
36
+ next unless n.chars.find { |c| ['.', '_'].include?(c) }
37
+
38
+ if n.chars.include?('.')
39
+ # Check underscore styled topic
40
+ underscored_topic = n.tr('.', '_')
41
+ error_occured = names_hash[underscored_topic] ? true : false
42
+ else
43
+ # Check dot styled topic
44
+ dot_topic = n.tr('_', '.')
45
+ error_occured = names_hash[dot_topic] ? true : false
46
+ end
47
+ end
48
+
49
+ next unless error_occured
50
+
51
+ [[%i[topics], :topics_namespaced_names_not_unique]]
52
+ end
27
53
  end
28
54
  end
29
55
  end
@@ -48,6 +48,17 @@ module Karafka
48
48
  [[%w[kafka], e.message]]
49
49
  end
50
50
  end
51
+
52
+ virtual do |data, errors|
53
+ next unless errors.empty?
54
+
55
+ value = data.fetch(:name)
56
+ namespacing_chars_count = value.chars.find_all { |c| ['.', '_'].include?(c) }.uniq.count
57
+
58
+ next if namespacing_chars_count <= 1
59
+
60
+ [[%w[name], :inconsistent_namespacing]]
61
+ end
51
62
  end
52
63
  end
53
64
  end
@@ -5,6 +5,6 @@ module Karafka
5
5
  module Contracts
6
6
  # Regexp for validating format of groups and topics
7
7
  # @note It is not nested inside of the contracts, as it is used by couple of them
8
- TOPIC_REGEXP = /\A(\w|-|\.)+\z/
8
+ TOPIC_REGEXP = /^[A-Za-z0-9\-_.]+$/
9
9
  end
10
10
  end
@@ -3,5 +3,5 @@
3
3
  # Main module namespace
4
4
  module Karafka
5
5
  # Current Karafka version
6
- VERSION = '2.0.30'
6
+ VERSION = '2.0.31'
7
7
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: karafka
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.30
4
+ version: 2.0.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld
@@ -35,7 +35,7 @@ cert_chain:
35
35
  Qf04B9ceLUaC4fPVEz10FyobjaFoY4i32xRto3XnrzeAgfEe4swLq8bQsR3w/EF3
36
36
  MGU0FeSV2Yj7Xc2x/7BzLK8xQn5l7Yy75iPF+KP3vVmDHnNl
37
37
  -----END CERTIFICATE-----
38
- date: 2023-01-31 00:00:00.000000000 Z
38
+ date: 2023-02-13 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: karafka-core
@@ -43,7 +43,7 @@ dependencies:
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 2.0.9
46
+ version: 2.0.11
47
47
  - - "<"
48
48
  - !ruby/object:Gem::Version
49
49
  version: 3.0.0
@@ -53,7 +53,7 @@ dependencies:
53
53
  requirements:
54
54
  - - ">="
55
55
  - !ruby/object:Gem::Version
56
- version: 2.0.9
56
+ version: 2.0.11
57
57
  - - "<"
58
58
  - !ruby/object:Gem::Version
59
59
  version: 3.0.0
@@ -356,7 +356,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
356
356
  - !ruby/object:Gem::Version
357
357
  version: '0'
358
358
  requirements: []
359
- rubygems_version: 3.4.1
359
+ rubygems_version: 3.4.6
360
360
  signing_key:
361
361
  specification_version: 4
362
362
  summary: Karafka is Ruby and Rails efficient Kafka processing framework.
metadata.gz.sig CHANGED
Binary file