karafka 2.0.30 → 2.0.31
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +7 -7
- data/config/locales/errors.yml +2 -0
- data/karafka.gemspec +1 -1
- data/lib/karafka/admin.rb +62 -5
- data/lib/karafka/contracts/consumer_group.rb +26 -0
- data/lib/karafka/contracts/topic.rb +11 -0
- data/lib/karafka/contracts.rb +1 -1
- data/lib/karafka/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +5 -5
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a4c598dcc6414c2a24f50452d5379c2a0aa26d7d1c7fd8d1b07f2af19a6e8125
|
|
4
|
+
data.tar.gz: 184a8b1e7bb1f62672f90904ce6c3fd5e2da5f1868bcb2a971a1e7872e8c3252
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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.
|
|
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.
|
|
5
|
-
karafka-core (>= 2.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.
|
|
32
|
+
karafka-core (2.0.11)
|
|
33
33
|
concurrent-ruby (>= 1.1)
|
|
34
|
-
karafka-rdkafka (>= 0.12)
|
|
35
|
-
karafka-rdkafka (0.12.
|
|
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.
|
|
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.
|
|
82
|
+
2.4.6
|
data/config/locales/errors.yml
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
data/lib/karafka/contracts.rb
CHANGED
data/lib/karafka/version.rb
CHANGED
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.
|
|
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-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|