karafka 2.0.29 → 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: 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