karafka 2.0.34 → 2.0.35

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: 36d890d825aaeaee5349dcc653d888da3a023c01a837864544a905db977569c4
4
- data.tar.gz: be442485812a05a030bab33da31a8e2fda684add8c4d59a0af78f517bb2519bd
3
+ metadata.gz: e2d2197fb0fe7eae8db43cc45ffbdcdc6da83d60731ae63b82dc4a24d852736e
4
+ data.tar.gz: 76b4b3f8ffb915b96a16f1eb83503283e5da46039fb952af383322773c4be551
5
5
  SHA512:
6
- metadata.gz: d92be137485c436c1ed02435669785422e6e4da194ab19b97dca31f70b530fe7e0ae4e6b0c7c54895dbceca2d8fe4ef1bdcabdb287affe06e377942062777979
7
- data.tar.gz: 0525b652373088a7a692134a6a4c89487e495e01934504d256a60ae7805c92f65a308d38c8d75ad806f39f5128d2d00865e10b1b4ae326c7dd60e7594c68558e
6
+ metadata.gz: 35d69a8fa9a26462f2167174d8700648909bbcf38363c5adef2f7ee42995b524c0d244bffe0bd76698f65df5475db78b38914f38d7eda239376c4031555ee885
7
+ data.tar.gz: 49a2256930ce83bc46b6471cf702b1ea2fe6f897a805f92e4dee7c3d9034a9625a44ecff0222b8396ed73858af5571cca4eaabca8d188a81312312c2225daa97
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Karafka framework changelog
2
2
 
3
+ ## 2.0.35 (2023-03-13)
4
+ - **[Feature]** Allow for defining topics config via the DSL and its automatic creation via CLI command.
5
+ - **[Feature]** Allow for full topics reset and topics repartitioning via the CLI.
6
+
3
7
  ## 2.0.34 (2023-03-04)
4
8
  - [Improvement] Attach an `embedded` tag to Karafka processes started using the embedded API.
5
9
  - [Change] Renamed `Datadog::Listener` to `Datadog::MetricsListener` for consistency. (#1124)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka (2.0.34)
4
+ karafka (2.0.35)
5
5
  karafka-core (>= 2.0.12, < 3.0.0)
6
6
  thor (>= 0.20)
7
7
  waterdrop (>= 2.4.10, < 3.0.0)
@@ -37,7 +37,7 @@ GEM
37
37
  mini_portile2 (~> 2.6)
38
38
  rake (> 12)
39
39
  mini_portile2 (2.8.1)
40
- minitest (5.17.0)
40
+ minitest (5.18.0)
41
41
  rake (13.0.6)
42
42
  rspec (3.12.0)
43
43
  rspec-core (~> 3.12.0)
@@ -61,12 +61,13 @@ GEM
61
61
  thor (1.2.1)
62
62
  tzinfo (2.0.6)
63
63
  concurrent-ruby (~> 1.0)
64
- waterdrop (2.4.11)
64
+ waterdrop (2.5.0)
65
65
  karafka-core (>= 2.0.12, < 3.0.0)
66
66
  zeitwerk (~> 2.3)
67
67
  zeitwerk (2.6.7)
68
68
 
69
69
  PLATFORMS
70
+ arm64-darwin-21
70
71
  x86_64-linux
71
72
 
72
73
  DEPENDENCIES
@@ -78,4 +79,4 @@ DEPENDENCIES
78
79
  simplecov
79
80
 
80
81
  BUNDLED WITH
81
- 2.4.6
82
+ 2.4.7
@@ -45,6 +45,10 @@ 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
+ structurable.partitions_format: needs to be more or equal to 1
49
+ structurable.active_format: needs to be true
50
+ structurable.replication_factor_format: needs to be more or equal to 1
51
+ structurable.details_format: needs to be a hash with only symbol keys
48
52
  inconsistent_namespacing: |
49
53
  needs to be consistent namespacing style
50
54
  disable this validation by setting config.strict_topics_namespacing to false
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ class Cli < Thor
5
+ # CLI actions related to Kafka cluster topics management
6
+ class Topics < Base
7
+ include Helpers::Colorize
8
+
9
+ desc 'Allows for the topics management (create, delete, reset, repartition)'
10
+ # @param action [String] action we want to take
11
+ def call(action = 'missing')
12
+ case action
13
+ when 'create'
14
+ create
15
+ when 'delete'
16
+ delete
17
+ when 'reset'
18
+ reset
19
+ when 'repartition'
20
+ repartition
21
+ when 'migrate'
22
+ migrate
23
+ else
24
+ raise ::ArgumentError, "Invalid topics action: #{action}"
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ # Creates topics based on the routing setup and configuration
31
+ def create
32
+ structurable_routing_topics.each do |topic|
33
+ name = topic.name
34
+
35
+ if existing_topics_names.include?(name)
36
+ puts "#{yellow('Skipping')} because topic #{name} already exists."
37
+ else
38
+ puts "Creating topic #{name}..."
39
+ Admin.create_topic(
40
+ name,
41
+ topic.structurable.partitions,
42
+ topic.structurable.replication_factor,
43
+ topic.structurable.details
44
+ )
45
+ puts "#{green('Created')} topic #{name}."
46
+ end
47
+ end
48
+ end
49
+
50
+ # Deletes routing based topics
51
+ def delete
52
+ structurable_routing_topics.each do |topic|
53
+ name = topic.name
54
+
55
+ if existing_topics_names.include?(name)
56
+ puts "Deleting topic #{name}..."
57
+ Admin.delete_topic(name)
58
+ puts "#{green('Deleted')} topic #{name}."
59
+ else
60
+ puts "#{yellow('Skipping')} because topic #{name} does not exist."
61
+ end
62
+ end
63
+ end
64
+
65
+ # Deletes routing based topics and re-creates them
66
+ def reset
67
+ delete
68
+
69
+ # We need to invalidate the metadata cache, otherwise we will think, that the topic
70
+ # already exists
71
+ @existing_topics = nil
72
+
73
+ create
74
+ end
75
+
76
+ # Creates missing topics and aligns the partitions count
77
+ def migrate
78
+ create
79
+
80
+ @existing_topics = nil
81
+
82
+ repartition
83
+ end
84
+
85
+ # Increases number of partitions on topics that have less partitions than defined
86
+ # Will **not** create topics if missing.
87
+ def repartition
88
+ existing_partitions = existing_topics.map do |topic|
89
+ [topic.fetch(:topic_name), topic.fetch(:partition_count)]
90
+ end.to_h
91
+
92
+ structurable_routing_topics.each do |topic|
93
+ name = topic.name
94
+
95
+ desired_count = topic.config.partitions
96
+ existing_count = existing_partitions.fetch(name, false)
97
+
98
+ if existing_count && existing_count < desired_count
99
+ puts "Increasing number of partitions to #{desired_count} on topic #{name}..."
100
+ Admin.create_partitions(name, desired_count)
101
+ change = desired_count - existing_count
102
+ puts "#{green('Created')} #{change} additional partitions on topic #{name}."
103
+ elsif existing_count
104
+ puts "#{yellow('Skipping')} because topic #{name} has #{existing_count} partitions."
105
+ else
106
+ puts "#{yellow('Skipping')} because topic #{name} does not exist."
107
+ end
108
+ end
109
+ end
110
+
111
+ # @return [Array<Karafka::Routing::Topic>] all available topics that can be managed
112
+ # @note If topic is defined in multiple consumer groups, first config will be used. This
113
+ # means, that this CLI will not work for simultaneous management of multiple clusters from
114
+ # a single CLI command execution flow.
115
+ def structurable_routing_topics
116
+ return @structurable_routing_topics if @structurable_routing_topics
117
+
118
+ collected_topics = {}
119
+
120
+ App.consumer_groups.each do |consumer_group|
121
+ consumer_group.topics.each do |topic|
122
+ # Skip topics that were explicitly disabled from management
123
+ next unless topic.structurable.active?
124
+
125
+ collected_topics[topic.name] ||= topic
126
+ end
127
+ end
128
+
129
+ @structurable_routing_topics = collected_topics.values
130
+ end
131
+
132
+ # @return [Array<Hash>] existing topics details
133
+ def existing_topics
134
+ @existing_topics ||= Admin.cluster_info.topics
135
+ end
136
+
137
+ # @return [Array<String>] names of already existing topics
138
+ def existing_topics_names
139
+ existing_topics.map { |topic| topic.fetch(:topic_name) }
140
+ end
141
+ end
142
+ end
143
+ end
@@ -15,6 +15,12 @@ module Karafka
15
15
  def red(string)
16
16
  "\033[0;31m#{string}\033[0m"
17
17
  end
18
+
19
+ # @param string [String] string we want to have in yellow
20
+ # @return [String] yellow string
21
+ def yellow(string)
22
+ "\033[1;33m#{string}\033[0m"
23
+ end
18
24
  end
19
25
  end
20
26
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Routing
5
+ module Features
6
+ class Structurable < Base
7
+ # Config for structurable feature
8
+ Config = Struct.new(
9
+ :active,
10
+ :partitions,
11
+ :replication_factor,
12
+ :details,
13
+ keyword_init: true
14
+ ) { alias_method :active?, :active }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Routing
5
+ module Features
6
+ class Structurable < Base
7
+ # Basic validation of the Kafka expected config details
8
+ class Contract < Contracts::Base
9
+ configure do |config|
10
+ config.error_messages = YAML.safe_load(
11
+ File.read(
12
+ File.join(Karafka.gem_root, 'config', 'locales', 'errors.yml')
13
+ )
14
+ ).fetch('en').fetch('validations').fetch('topic')
15
+ end
16
+
17
+ nested :structurable do
18
+ required(:active) { |val| [true, false].include?(val) }
19
+ required(:partitions) { |val| val.is_a?(Integer) && val.positive? }
20
+ required(:replication_factor) { |val| val.is_a?(Integer) && val.positive? }
21
+ required(:details) do |val|
22
+ val.is_a?(Hash) &&
23
+ val.keys.all? { |key| key.is_a?(Symbol) }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Routing
5
+ module Features
6
+ class Structurable < Base
7
+ # Extension for managing Kafka topic configuration
8
+ module Topic
9
+ # @param active [Boolean] is the topic structure management feature active
10
+ # @param partitions [Integer]
11
+ # @param replication_factor [Integer]
12
+ # @param details [Hash] extra configuration for the topic
13
+ # @return [Config] defined structure
14
+ def config(active: true, partitions: 1, replication_factor: 1, **details)
15
+ @structurable ||= Config.new(
16
+ active: active,
17
+ partitions: partitions,
18
+ replication_factor: replication_factor,
19
+ details: details
20
+ )
21
+ end
22
+
23
+ # @return [Config] config details
24
+ def structurable
25
+ config
26
+ end
27
+
28
+ # @return [true] structurable is always active
29
+ def structurable?
30
+ structurable.active?
31
+ end
32
+
33
+ # @return [Hash] topic with all its native configuration options plus structurable
34
+ # settings
35
+ def to_h
36
+ super.merge(
37
+ structurable: structurable.to_h
38
+ ).freeze
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Routing
5
+ module Features
6
+ # This feature allows to store per topic structure that can be later on used to bootstrap
7
+ # topics structure for test/development, etc. This allows to share the same set of settings
8
+ # for topics despite the environment. Pretty much similar to how the `structure.sql` or
9
+ # `schema.rb` operate for SQL dbs.
10
+ class Structurable < Base
11
+ end
12
+ end
13
+ end
14
+ end
@@ -53,6 +53,11 @@ class KarafkaApp < Karafka::App
53
53
  # active_job_topic :default
54
54
  <% end -%>
55
55
  topic :example do
56
+ # Uncomment this if you want Karafka to manage your topics configuration
57
+ # Managing topics configuration via routing will allow you to ensure config consistency
58
+ # across multiple environments
59
+ #
60
+ # config(partitions: 2, 'cleanup.policy': 'compact')
56
61
  consumer ExampleConsumer
57
62
  end
58
63
  end
@@ -3,5 +3,5 @@
3
3
  # Main module namespace
4
4
  module Karafka
5
5
  # Current Karafka version
6
- VERSION = '2.0.34'
6
+ VERSION = '2.0.35'
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.34
4
+ version: 2.0.35
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-03-04 00:00:00.000000000 Z
38
+ date: 2023-03-13 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: karafka-core
@@ -168,6 +168,7 @@ files:
168
168
  - lib/karafka/cli/info.rb
169
169
  - lib/karafka/cli/install.rb
170
170
  - lib/karafka/cli/server.rb
171
+ - lib/karafka/cli/topics.rb
171
172
  - lib/karafka/connection/client.rb
172
173
  - lib/karafka/connection/consumer_group_coordinator.rb
173
174
  - lib/karafka/connection/listener.rb
@@ -309,6 +310,10 @@ files:
309
310
  - lib/karafka/routing/features/manual_offset_management/config.rb
310
311
  - lib/karafka/routing/features/manual_offset_management/contract.rb
311
312
  - lib/karafka/routing/features/manual_offset_management/topic.rb
313
+ - lib/karafka/routing/features/structurable.rb
314
+ - lib/karafka/routing/features/structurable/config.rb
315
+ - lib/karafka/routing/features/structurable/contract.rb
316
+ - lib/karafka/routing/features/structurable/topic.rb
312
317
  - lib/karafka/routing/proxy.rb
313
318
  - lib/karafka/routing/router.rb
314
319
  - lib/karafka/routing/subscription_group.rb
metadata.gz.sig CHANGED
Binary file