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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a258a78f3df80b4cda4f315f56ef4f7fb48003f63d0d58140c189b01b3f4875
4
- data.tar.gz: c267cb96bb8a972a2255f4a1298adde63678be4502b4ec8573af9c8a940435b4
3
+ metadata.gz: a4c598dcc6414c2a24f50452d5379c2a0aa26d7d1c7fd8d1b07f2af19a6e8125
4
+ data.tar.gz: 184a8b1e7bb1f62672f90904ce6c3fd5e2da5f1868bcb2a971a1e7872e8c3252
5
5
  SHA512:
6
- metadata.gz: beed9b0cbc83249d0bf227edb859142888d748dab6a972bf58c2d7e38ad578292544948bd9f2f25edbeebe6b37d1f0d20d47fc5e15d3d12420964447d414c54a
7
- data.tar.gz: 7da728f75e5540d339887d2fb3bee4787016bdcd16a56f29b4f9c0b3e9f4ff45f1d6f0e843d25bf3e7a31e05ea3a320e174a005a149f76156618dc70327e71de
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,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.29)
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)
@@ -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.1)
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.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)
@@ -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.5)
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.5
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
 
@@ -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)
@@ -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
- active_routing_config = Karafka::App.config.internal.routing.active
22
- active_routing_config.consumer_groups = cli.options[:consumer_groups]
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
- optional(:consumer_groups) { |cg| cg.is_a?(Array) }
16
- optional(:subscription_groups) { |sg| sg.is_a?(Array) }
17
- optional(:topics) { |topics| topics.is_a?(Array) }
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
- virtual do |data, errors|
20
- next unless errors.empty?
21
- next unless data.key?(:consumer_groups)
23
+ virtual do |data, errors|
24
+ next unless errors.empty?
22
25
 
23
- value = data.fetch(:consumer_groups)
26
+ value = data.fetch(:"#{action}_consumer_groups")
24
27
 
25
- # If there were no consumer_groups declared in the server cli, it means that we will
26
- # run all of them and no need to validate them here at all
27
- next if value.empty?
28
- next if (value - Karafka::App.consumer_groups.map(&:name)).empty?
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
- # Found unknown consumer groups
31
- [[%i[consumer_groups], :consumer_groups_inclusion]]
32
- end
33
+ # Found unknown consumer groups
34
+ [[[:"#{action}_consumer_groups"], :consumer_groups_inclusion]]
35
+ end
33
36
 
34
- virtual do |data, errors|
35
- next unless errors.empty?
36
- next unless data.key?(:subscription_groups)
37
+ virtual do |data, errors|
38
+ next unless errors.empty?
37
39
 
38
- value = data.fetch(:subscription_groups)
40
+ value = data.fetch(:"#{action}_subscription_groups")
39
41
 
40
- # If there were no subscription_groups declared in the server cli, it means that we will
41
- # run all of them and no need to validate them here at all
42
- next if value.empty?
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
- subscription_groups = Karafka::App
45
- .consumer_groups
46
- .map(&:subscription_groups)
47
- .flatten
48
- .map(&:name)
46
+ subscription_groups = Karafka::App
47
+ .consumer_groups
48
+ .map(&:subscription_groups)
49
+ .flatten
50
+ .map(&:name)
49
51
 
50
- next if (value - subscription_groups).empty?
52
+ next if (value - subscription_groups).empty?
51
53
 
52
- # Found unknown subscription groups
53
- [[%i[subscription_groups], :subscription_groups_inclusion]]
54
- end
54
+ # Found unknown subscription groups
55
+ [[[:"#{action}_subscription_groups"], :subscription_groups_inclusion]]
56
+ end
55
57
 
56
- virtual do |data, errors|
57
- next unless errors.empty?
58
- next unless data.key?(:topics)
58
+ virtual do |data, errors|
59
+ next unless errors.empty?
59
60
 
60
- value = data.fetch(:topics)
61
+ value = data.fetch(:"#{action}_topics")
61
62
 
62
- # If there were no topics declared in the server cli, it means that we will
63
- # run all of them and no need to validate them here at all
64
- next if value.empty?
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
- topics = Karafka::App
67
- .consumer_groups
68
- .map(&:subscription_groups)
69
- .flatten
70
- .map(&:topics)
71
- .map { |gtopics| gtopics.map(&:name) }
72
- .flatten
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
- next if (value - topics).empty?
75
+ next if (value - topics).empty?
75
76
 
76
- # Found unknown topics
77
- [[%i[topics], :topics_inclusion]]
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[topics], :topics_missing]]
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
@@ -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
@@ -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
- cgs = Karafka::App.config.internal.routing.active.consumer_groups
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
- sgs = Karafka::App.config.internal.routing.active.subscription_groups
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
- topics = Karafka::App.config.internal.routing.active.topics
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
@@ -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.active.to_h
36
+ Karafka::App.config.internal.routing.activity_manager.to_h
37
37
  )
38
38
 
39
39
  process.on_sigint { stop }
@@ -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 should be overwritten by the CLI command
115
- setting :active do
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
@@ -3,5 +3,5 @@
3
3
  # Main module namespace
4
4
  module Karafka
5
5
  # Current Karafka version
6
- VERSION = '2.0.29'
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.29
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-30 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
@@ -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.1
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