karafka 2.0.29 → 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 +16 -0
- data/Gemfile.lock +9 -9
- data/README.md +2 -1
- data/config/locales/errors.yml +2 -0
- data/karafka.gemspec +1 -1
- data/lib/karafka/admin.rb +62 -5
- data/lib/karafka/cli/server.rb +50 -4
- data/lib/karafka/contracts/consumer_group.rb +26 -0
- data/lib/karafka/contracts/server_cli_options.rb +50 -48
- data/lib/karafka/contracts/topic.rb +11 -0
- data/lib/karafka/contracts.rb +1 -1
- data/lib/karafka/routing/activity_manager.rb +84 -0
- data/lib/karafka/routing/consumer_group.rb +1 -4
- data/lib/karafka/routing/subscription_group.rb +1 -4
- data/lib/karafka/routing/topic.rb +1 -4
- data/lib/karafka/server.rb +1 -1
- data/lib/karafka/setup/config.rb +2 -6
- data/lib/karafka/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +6 -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,21 @@
|
|
|
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
|
+
|
|
11
|
+
## 2.0.30 (2022-01-31)
|
|
12
|
+
- [Improvement] Alias `--consumer-groups` with `--include-consumer-groups`
|
|
13
|
+
- [Improvement] Alias `--subscription-groups` with `--include-subscription-groups`
|
|
14
|
+
- [Improvement] Alias `--topics` with `--include-topics`
|
|
15
|
+
- [Improvement] Introduce `--exclude-consumer-groups` for ability to exclude certain consumer groups from running
|
|
16
|
+
- [Improvement] Introduce `--exclude-subscription-groups` for ability to exclude certain subscription groups from running
|
|
17
|
+
- [Improvement] Introduce `--exclude-topics` for ability to exclude certain topics from running
|
|
18
|
+
|
|
3
19
|
## 2.0.29 (2023-01-30)
|
|
4
20
|
- [Improvement] Make sure, that the `Karafka#producer` instance has the `LoggerListener` enabled in the install template, so Karafka by default prints both consumer and producer info.
|
|
5
21
|
- [Improvement] Extract the code loading capabilities of Karafka console from the executable, so web can use it to provide CLI commands.
|
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)
|
|
@@ -25,14 +25,14 @@ GEM
|
|
|
25
25
|
factory_bot (6.2.1)
|
|
26
26
|
activesupport (>= 5.0.0)
|
|
27
27
|
ffi (1.15.5)
|
|
28
|
-
globalid (1.0
|
|
28
|
+
globalid (1.1.0)
|
|
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)
|
|
@@ -59,7 +59,7 @@ GEM
|
|
|
59
59
|
simplecov-html (0.12.3)
|
|
60
60
|
simplecov_json_formatter (0.1.4)
|
|
61
61
|
thor (1.2.1)
|
|
62
|
-
tzinfo (2.0.
|
|
62
|
+
tzinfo (2.0.6)
|
|
63
63
|
concurrent-ruby (~> 1.0)
|
|
64
64
|
waterdrop (2.4.10)
|
|
65
65
|
karafka-core (>= 2.0.9, < 3.0.0)
|
|
@@ -79,4 +79,4 @@ DEPENDENCIES
|
|
|
79
79
|
simplecov
|
|
80
80
|
|
|
81
81
|
BUNDLED WITH
|
|
82
|
-
2.4.
|
|
82
|
+
2.4.6
|
data/README.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
Karafka is a Ruby and Rails multi-threaded efficient Kafka processing framework that:
|
|
12
12
|
|
|
13
|
+
- Has a built-in [Web UI](https://karafka.io/docs/Web-UI-Features/) providing a convenient way to monitor and manage Karafka-based applications.
|
|
13
14
|
- Supports parallel processing in [multiple threads](https://karafka.io/docs/Concurrency-and-multithreading) (also for a [single topic partition](https://karafka.io/docs/Pro-Virtual-Partitions) work)
|
|
14
15
|
- [Automatically integrates](https://karafka.io/docs/Integrating-with-Ruby-on-Rails-and-other-frameworks#integrating-with-ruby-on-rails) with Ruby on Rails
|
|
15
16
|
- Has [ActiveJob backend](https://karafka.io/docs/Active-Job) support (including [ordered jobs](https://karafka.io/docs/Pro-Enhanced-Active-Job#ordered-jobs))
|
|
@@ -83,7 +84,7 @@ bundle exec karafka server
|
|
|
83
84
|
|
|
84
85
|
## Want to Upgrade? LGPL is not for you? Want to help?
|
|
85
86
|
|
|
86
|
-
I also sell Karafka Pro subscriptions. It includes a commercial-friendly license, priority support, architecture consultations, and high throughput data processing-related features (virtual partitions, long-running jobs, and more).
|
|
87
|
+
I also sell Karafka Pro subscriptions. It includes a commercial-friendly license, priority support, architecture consultations, enhanced Web UI and high throughput data processing-related features (virtual partitions, long-running jobs, and more).
|
|
87
88
|
|
|
88
89
|
**20%** of the income will be distributed back to other OSS projects that Karafka uses under the hood.
|
|
89
90
|
|
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)
|
data/lib/karafka/cli/server.rb
CHANGED
|
@@ -7,27 +7,73 @@ module Karafka
|
|
|
7
7
|
class Server < Base
|
|
8
8
|
include Helpers::Colorize
|
|
9
9
|
|
|
10
|
+
# Types of things we can include / exclude from the routing via the CLI options
|
|
11
|
+
SUPPORTED_TYPES = ::Karafka::Routing::ActivityManager::SUPPORTED_TYPES
|
|
12
|
+
|
|
13
|
+
private_constant :SUPPORTED_TYPES
|
|
14
|
+
|
|
10
15
|
desc 'Start the Karafka server (short-cut alias: "s")'
|
|
16
|
+
|
|
11
17
|
option aliases: 's'
|
|
18
|
+
|
|
19
|
+
# Thor does not work well with many aliases combinations, hence we remap the aliases
|
|
20
|
+
# by ourselves in the code
|
|
12
21
|
option :consumer_groups, type: :array, default: [], aliases: :g
|
|
13
22
|
option :subscription_groups, type: :array, default: []
|
|
14
23
|
option :topics, type: :array, default: []
|
|
15
24
|
|
|
25
|
+
%i[
|
|
26
|
+
include
|
|
27
|
+
exclude
|
|
28
|
+
].each do |action|
|
|
29
|
+
SUPPORTED_TYPES.each do |type|
|
|
30
|
+
option(
|
|
31
|
+
"#{action}_#{type}",
|
|
32
|
+
type: :array,
|
|
33
|
+
default: []
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
16
38
|
# Start the Karafka server
|
|
17
39
|
def call
|
|
18
40
|
# Print our banner and info in the dev mode
|
|
19
41
|
print_marketing_info if Karafka::App.env.development?
|
|
20
42
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
active_routing_config.subscription_groups = cli.options[:subscription_groups]
|
|
24
|
-
active_routing_config.topics = cli.options[:topics]
|
|
43
|
+
register_inclusions(cli)
|
|
44
|
+
register_exclusions(cli)
|
|
25
45
|
|
|
26
46
|
Karafka::Server.run
|
|
27
47
|
end
|
|
28
48
|
|
|
29
49
|
private
|
|
30
50
|
|
|
51
|
+
# Registers things we want to include (if defined)
|
|
52
|
+
# @param cli [Karafka::Cli] Thor cli handler
|
|
53
|
+
def register_inclusions(cli)
|
|
54
|
+
activities = ::Karafka::App.config.internal.routing.activity_manager
|
|
55
|
+
|
|
56
|
+
SUPPORTED_TYPES.each do |type|
|
|
57
|
+
v1 = cli.options[type] || []
|
|
58
|
+
v2 = cli.options[:"include_#{type}"] || []
|
|
59
|
+
names = v1 + v2
|
|
60
|
+
|
|
61
|
+
names.each { |name| activities.include(type, name) }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Registers things we want to exclude (if defined)
|
|
66
|
+
# @param cli [Karafka::Cli] Thor cli handler
|
|
67
|
+
def register_exclusions(cli)
|
|
68
|
+
activities = ::Karafka::App.config.internal.routing.activity_manager
|
|
69
|
+
|
|
70
|
+
activities.class::SUPPORTED_TYPES.each do |type|
|
|
71
|
+
names = cli.options[:"exclude_#{type}"] || []
|
|
72
|
+
|
|
73
|
+
names.each { |name| activities.exclude(type, name) }
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
31
77
|
# Prints marketing info
|
|
32
78
|
def print_marketing_info
|
|
33
79
|
Karafka.logger.info Info::BANNER
|
|
@@ -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
|
|
@@ -12,69 +12,71 @@ module Karafka
|
|
|
12
12
|
).fetch('en').fetch('validations').fetch('server_cli_options')
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
%i[
|
|
16
|
+
include
|
|
17
|
+
exclude
|
|
18
|
+
].each do |action|
|
|
19
|
+
optional(:"#{action}_consumer_groups") { |cg| cg.is_a?(Array) }
|
|
20
|
+
optional(:"#{action}_subscription_groups") { |sg| sg.is_a?(Array) }
|
|
21
|
+
optional(:"#{action}_topics") { |topics| topics.is_a?(Array) }
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
next unless data.key?(:consumer_groups)
|
|
23
|
+
virtual do |data, errors|
|
|
24
|
+
next unless errors.empty?
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
value = data.fetch(:"#{action}_consumer_groups")
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
# If there were no consumer_groups declared in the server cli, it means that we will
|
|
29
|
+
# run all of them and no need to validate them here at all
|
|
30
|
+
next if value.empty?
|
|
31
|
+
next if (value - Karafka::App.consumer_groups.map(&:name)).empty?
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
# Found unknown consumer groups
|
|
34
|
+
[[[:"#{action}_consumer_groups"], :consumer_groups_inclusion]]
|
|
35
|
+
end
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
next unless data.key?(:subscription_groups)
|
|
37
|
+
virtual do |data, errors|
|
|
38
|
+
next unless errors.empty?
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
value = data.fetch(:"#{action}_subscription_groups")
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
# If there were no subscription_groups declared in the server cli, it means that we will
|
|
43
|
+
# run all of them and no need to validate them here at all
|
|
44
|
+
next if value.empty?
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
subscription_groups = Karafka::App
|
|
47
|
+
.consumer_groups
|
|
48
|
+
.map(&:subscription_groups)
|
|
49
|
+
.flatten
|
|
50
|
+
.map(&:name)
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
next if (value - subscription_groups).empty?
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
# Found unknown subscription groups
|
|
55
|
+
[[[:"#{action}_subscription_groups"], :subscription_groups_inclusion]]
|
|
56
|
+
end
|
|
55
57
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
next unless data.key?(:topics)
|
|
58
|
+
virtual do |data, errors|
|
|
59
|
+
next unless errors.empty?
|
|
59
60
|
|
|
60
|
-
|
|
61
|
+
value = data.fetch(:"#{action}_topics")
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
# If there were no topics declared in the server cli, it means that we will
|
|
64
|
+
# run all of them and no need to validate them here at all
|
|
65
|
+
next if value.empty?
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
topics = Karafka::App
|
|
68
|
+
.consumer_groups
|
|
69
|
+
.map(&:subscription_groups)
|
|
70
|
+
.flatten
|
|
71
|
+
.map(&:topics)
|
|
72
|
+
.map { |gtopics| gtopics.map(&:name) }
|
|
73
|
+
.flatten
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
next if (value - topics).empty?
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
# Found unknown topics
|
|
78
|
+
[[[:"#{action}_topics"], :topics_inclusion]]
|
|
79
|
+
end
|
|
78
80
|
end
|
|
79
81
|
|
|
80
82
|
# Makes sure we have anything to subscribe to when we start the server
|
|
@@ -83,7 +85,7 @@ module Karafka
|
|
|
83
85
|
|
|
84
86
|
next unless Karafka::App.subscription_groups.empty?
|
|
85
87
|
|
|
86
|
-
[[%i[
|
|
88
|
+
[[%i[include_topics], :topics_missing]]
|
|
87
89
|
end
|
|
88
90
|
end
|
|
89
91
|
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
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Karafka
|
|
4
|
+
module Routing
|
|
5
|
+
# Allows us to get track of which consumer groups, subscription groups and topics are enabled
|
|
6
|
+
# or disabled via CLI
|
|
7
|
+
class ActivityManager
|
|
8
|
+
# Supported types of inclusions and exclusions
|
|
9
|
+
SUPPORTED_TYPES = %i[
|
|
10
|
+
consumer_groups
|
|
11
|
+
subscription_groups
|
|
12
|
+
topics
|
|
13
|
+
].freeze
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@included = Hash.new { |h, k| h[k] = [] }
|
|
17
|
+
@excluded = Hash.new { |h, k| h[k] = [] }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Adds resource to included/active
|
|
21
|
+
# @param type [Symbol] type for inclusion
|
|
22
|
+
# @param name [String] name of the element
|
|
23
|
+
def include(type, name)
|
|
24
|
+
validate!(type)
|
|
25
|
+
|
|
26
|
+
@included[type] << name
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Adds resource to excluded
|
|
30
|
+
# @param type [Symbol] type for inclusion
|
|
31
|
+
# @param name [String] name of the element
|
|
32
|
+
def exclude(type, name)
|
|
33
|
+
validate!(type)
|
|
34
|
+
|
|
35
|
+
@excluded[type] << name
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @param type [Symbol] type for inclusion
|
|
39
|
+
# @param name [String] name of the element
|
|
40
|
+
# @return [Boolean] is the given resource active or not
|
|
41
|
+
def active?(type, name)
|
|
42
|
+
validate!(type)
|
|
43
|
+
|
|
44
|
+
included = @included[type]
|
|
45
|
+
excluded = @excluded[type]
|
|
46
|
+
|
|
47
|
+
# If nothing defined, all active by default
|
|
48
|
+
return true if included.empty? && excluded.empty?
|
|
49
|
+
# Inclusion supersedes exclusion in case someone wrote both
|
|
50
|
+
return true if !included.empty? && included.include?(name)
|
|
51
|
+
|
|
52
|
+
# If there are exclusions but our is not excluded and no inclusions or included, it's ok
|
|
53
|
+
!excluded.empty? &&
|
|
54
|
+
!excluded.include?(name) &&
|
|
55
|
+
(included.empty? || included.include?(name))
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @return [Hash] accumulated data in a hash for validations
|
|
59
|
+
def to_h
|
|
60
|
+
(
|
|
61
|
+
SUPPORTED_TYPES.map { |type| ["include_#{type}".to_sym, @included[type]] } +
|
|
62
|
+
SUPPORTED_TYPES.map { |type| ["exclude_#{type}".to_sym, @excluded[type]] }
|
|
63
|
+
).to_h
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Clears the manager
|
|
67
|
+
def clear
|
|
68
|
+
@included.clear
|
|
69
|
+
@excluded.clear
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# Checks if the type we want to register is supported
|
|
75
|
+
#
|
|
76
|
+
# @param type [Symbol] type for inclusion
|
|
77
|
+
def validate!(type)
|
|
78
|
+
return if SUPPORTED_TYPES.include?(type)
|
|
79
|
+
|
|
80
|
+
raise(::Karafka::Errors::UnsupportedCaseError, type)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -31,10 +31,7 @@ module Karafka
|
|
|
31
31
|
|
|
32
32
|
# @return [Boolean] true if this consumer group should be active in our current process
|
|
33
33
|
def active?
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
# When empty it means no groups were specified, hence all should be used
|
|
37
|
-
cgs.empty? || cgs.include?(name)
|
|
34
|
+
Karafka::App.config.internal.routing.activity_manager.active?(:consumer_groups, name)
|
|
38
35
|
end
|
|
39
36
|
|
|
40
37
|
# Builds a topic representation inside of a current consumer group route
|
|
@@ -58,10 +58,7 @@ module Karafka
|
|
|
58
58
|
|
|
59
59
|
# @return [Boolean] is this subscription group one of active once
|
|
60
60
|
def active?
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
# When empty it means no groups were specified, hence all should be used
|
|
64
|
-
sgs.empty? || sgs.include?(name)
|
|
61
|
+
Karafka::App.config.internal.routing.activity_manager.active?(:subscription_groups, name)
|
|
65
62
|
end
|
|
66
63
|
|
|
67
64
|
private
|
|
@@ -87,10 +87,7 @@ module Karafka
|
|
|
87
87
|
# Never active if disabled via routing
|
|
88
88
|
return false unless @active
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# When empty it means no topics were specified, hence all should be used
|
|
93
|
-
topics.empty? || topics.include?(name)
|
|
90
|
+
Karafka::App.config.internal.routing.activity_manager.active?(:topics, name)
|
|
94
91
|
end
|
|
95
92
|
|
|
96
93
|
# @return [Hash] hash with all the topic attributes
|
data/lib/karafka/server.rb
CHANGED
|
@@ -33,7 +33,7 @@ module Karafka
|
|
|
33
33
|
# We cannot validate this during the start because config needs to be populated and routes
|
|
34
34
|
# need to be defined.
|
|
35
35
|
Contracts::ServerCliOptions.new.validate!(
|
|
36
|
-
Karafka::App.config.internal.routing.
|
|
36
|
+
Karafka::App.config.internal.routing.activity_manager.to_h
|
|
37
37
|
)
|
|
38
38
|
|
|
39
39
|
process.on_sigint { stop }
|
data/lib/karafka/setup/config.rb
CHANGED
|
@@ -111,12 +111,8 @@ module Karafka
|
|
|
111
111
|
setting :subscription_groups_builder, default: Routing::SubscriptionGroupsBuilder.new
|
|
112
112
|
|
|
113
113
|
# Internally assigned list of limits on routings active for the current process
|
|
114
|
-
# This
|
|
115
|
-
setting :
|
|
116
|
-
setting :consumer_groups, default: [].freeze
|
|
117
|
-
setting :subscription_groups, default: [].freeze
|
|
118
|
-
setting :topics, default: [].freeze
|
|
119
|
-
end
|
|
114
|
+
# This can be altered by the CLI command
|
|
115
|
+
setting :activity_manager, default: Routing::ActivityManager.new
|
|
120
116
|
end
|
|
121
117
|
|
|
122
118
|
setting :processing do
|
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
|
|
@@ -289,6 +289,7 @@ files:
|
|
|
289
289
|
- lib/karafka/processing/worker.rb
|
|
290
290
|
- lib/karafka/processing/workers_batch.rb
|
|
291
291
|
- lib/karafka/railtie.rb
|
|
292
|
+
- lib/karafka/routing/activity_manager.rb
|
|
292
293
|
- lib/karafka/routing/builder.rb
|
|
293
294
|
- lib/karafka/routing/consumer_group.rb
|
|
294
295
|
- lib/karafka/routing/consumer_mapper.rb
|
|
@@ -355,7 +356,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
355
356
|
- !ruby/object:Gem::Version
|
|
356
357
|
version: '0'
|
|
357
358
|
requirements: []
|
|
358
|
-
rubygems_version: 3.4.
|
|
359
|
+
rubygems_version: 3.4.6
|
|
359
360
|
signing_key:
|
|
360
361
|
specification_version: 4
|
|
361
362
|
summary: Karafka is Ruby and Rails efficient Kafka processing framework.
|
metadata.gz.sig
CHANGED
|
Binary file
|