karafka 2.2.7 → 2.2.8.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +12 -0
  4. data/Gemfile.lock +3 -5
  5. data/bin/karafka +2 -3
  6. data/docker-compose.yml +3 -1
  7. data/karafka.gemspec +1 -2
  8. data/lib/karafka/base_consumer.rb +1 -0
  9. data/lib/karafka/cli/base.rb +45 -34
  10. data/lib/karafka/cli/console.rb +5 -4
  11. data/lib/karafka/cli/help.rb +24 -0
  12. data/lib/karafka/cli/info.rb +2 -2
  13. data/lib/karafka/cli/install.rb +4 -4
  14. data/lib/karafka/cli/server.rb +68 -33
  15. data/lib/karafka/cli/topics.rb +1 -1
  16. data/lib/karafka/cli.rb +23 -19
  17. data/lib/karafka/connection/client.rb +9 -4
  18. data/lib/karafka/connection/rebalance_manager.rb +36 -21
  19. data/lib/karafka/errors.rb +3 -0
  20. data/lib/karafka/instrumentation/callbacks/rebalance.rb +64 -0
  21. data/lib/karafka/instrumentation/notifications.rb +5 -1
  22. data/lib/karafka/instrumentation/vendors/appsignal/base.rb +30 -0
  23. data/lib/karafka/instrumentation/vendors/appsignal/client.rb +122 -0
  24. data/lib/karafka/instrumentation/vendors/appsignal/dashboard.json +222 -0
  25. data/lib/karafka/instrumentation/vendors/appsignal/errors_listener.rb +30 -0
  26. data/lib/karafka/instrumentation/vendors/appsignal/metrics_listener.rb +331 -0
  27. data/lib/karafka/instrumentation/vendors/datadog/metrics_listener.rb +2 -2
  28. data/lib/karafka/patches/rdkafka/bindings.rb +22 -39
  29. data/lib/karafka/patches/rdkafka/opaque.rb +36 -0
  30. data/lib/karafka/pro/processing/coordinator.rb +6 -7
  31. data/lib/karafka/pro/processing/strategies/vp/default.rb +20 -0
  32. data/lib/karafka/version.rb +1 -1
  33. data/lib/karafka.rb +1 -1
  34. data.tar.gz.sig +0 -0
  35. metadata +14 -20
  36. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6a42d67752052bcf8f29fb683ed8ffb5fce7675c155b73269c4654681913f7b
4
- data.tar.gz: b1bfc5bdad87c27111d8aee50302593133460f0eac47161f3c3872dc726d3b68
3
+ metadata.gz: facd28537bbd9b1f5a7e6956c82b704a97efafdfdcea5ed9959991f129ba2ed4
4
+ data.tar.gz: 4b6ca5058a07fadf7c95fa96eb08ff7820b44d4bafc43ebdaf0a7fe16cb35fd2
5
5
  SHA512:
6
- metadata.gz: b1e46475db36dc2fc837aa68b1639ad43b94a59afc72dd7287c60fac5f504f55c1ed68f9a1527a4eb1f6743801d38ba44ac6eef6c9d69a6b2ae4e4fbf3034b98
7
- data.tar.gz: 329fe59c9bbede3367c9bb3624c69652111f9387360d28b8d9e83bb0a184ea0e524d87d3f47afc400446f48993a57a41c4c171ae5e16c5413c7a496e88fc0421
6
+ metadata.gz: fd8cda16faa8d1267b934d2ccc189e6981c21be8cc4fed60042776a6370c93481b99981117d2572a52ada12ea9268877e339a5007284aa2413135ace5a078241
7
+ data.tar.gz: e765bb3a3c6de52bd6dbd12a7268d18c03cb1454068dff19ebc49d1c5a7850058b8b0853e744c6a16f07bc7f3883bf8681df19a10c0babc70defca1dbdee2b19
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Karafka framework changelog
2
2
 
3
+ ## 2.2.8 (Unreleased)
4
+ - **[Feature]** Introduce Appsignal integration for errors and metrics tracking.
5
+ - [Improvement] Expose `#synchronize` for VPs to allow for locks when cross-VP consumers work is needed.
6
+ - [Improvement] Provide `#collapse_until!` direct consumer API to allow for collapsed virtual partitions consumer operations together with the Filtering API for advanced use-cases.
7
+ - [Refactor] Reorganize how rebalance events are propagated from `librdkafka` to Karafka. Replace `connection.client.rebalance_callback` with `rebalance.partitions_assigned` and `rebalance.partitions_revoked`. Introduce two extra events: `rebalance.partitions_assign` and `rebalance.partitions_revoke` to handle pre-rebalance future work.
8
+ - [Refactor] Remove `thor` as a CLI layer and rely on Ruby `OptParser`
9
+
10
+ ### Upgrade notes
11
+
12
+ 1. Unless you were using `connection.client.rebalance_callback` which was considered private, nothing.
13
+ 2. None of the CLI commands should change but `thor` has been removed so please report if you find any bugs.
14
+
3
15
  ## 2.2.7 (2023-10-07)
4
16
  - **[Feature]** Introduce Inline Insights to both OSS and Pro. Inline Insights allow you to get the Kafka insights/metrics from the consumer instance and use them to alter the processing flow. In Pro, there's an extra filter flow allowing to ensure, that the insights exist during consumption.
5
17
  - [Enhancement] Make sure, that subscription groups ids are unique by including their consumer group id in them similar to how topics ids are handled (not a breaking change).
data/Gemfile.lock CHANGED
@@ -1,9 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- karafka (2.2.7)
4
+ karafka (2.2.8.beta1)
5
5
  karafka-core (>= 2.2.2, < 2.3.0)
6
- thor (>= 0.20)
7
6
  waterdrop (>= 2.6.6, < 3.0.0)
8
7
  zeitwerk (~> 2.3)
9
8
 
@@ -37,7 +36,7 @@ GEM
37
36
  ffi (~> 1.15)
38
37
  mini_portile2 (~> 2.6)
39
38
  rake (> 12)
40
- karafka-web (0.7.5)
39
+ karafka-web (0.7.6)
41
40
  erubi (~> 1.4)
42
41
  karafka (>= 2.2.6, < 3.0.0)
43
42
  karafka-core (>= 2.2.2, < 3.0.0)
@@ -68,8 +67,7 @@ GEM
68
67
  simplecov_json_formatter (~> 0.1)
69
68
  simplecov-html (0.12.3)
70
69
  simplecov_json_formatter (0.1.4)
71
- thor (1.2.2)
72
- tilt (2.2.0)
70
+ tilt (2.3.0)
73
71
  tzinfo (2.0.6)
74
72
  concurrent-ruby (~> 1.0)
75
73
  waterdrop (2.6.7)
data/bin/karafka CHANGED
@@ -6,6 +6,5 @@ require 'karafka'
6
6
  # our bin/karafka cli
7
7
  ENV['KARAFKA_CLI'] = 'true'
8
8
 
9
- Karafka::Cli::Base.load
10
- Karafka::Cli.prepare
11
- Karafka::Cli.start
9
+ ::Karafka::Cli::Base.load
10
+ ::Karafka::Cli.start
data/docker-compose.yml CHANGED
@@ -3,7 +3,7 @@ version: '2'
3
3
  services:
4
4
  kafka:
5
5
  container_name: kafka
6
- image: confluentinc/cp-kafka:7.5.0
6
+ image: confluentinc/cp-kafka:7.5.1
7
7
 
8
8
  ports:
9
9
  - 9092:9092
@@ -21,3 +21,5 @@ services:
21
21
  KAFKA_CONTROLLER_QUORUM_VOTERS: 1@127.0.0.1:9093
22
22
  ALLOW_PLAINTEXT_LISTENER: 'yes'
23
23
  KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'true'
24
+ KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
25
+ KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
data/karafka.gemspec CHANGED
@@ -22,7 +22,6 @@ Gem::Specification.new do |spec|
22
22
  DESC
23
23
 
24
24
  spec.add_dependency 'karafka-core', '>= 2.2.2', '< 2.3.0'
25
- spec.add_dependency 'thor', '>= 0.20'
26
25
  spec.add_dependency 'waterdrop', '>= 2.6.6', '< 3.0.0'
27
26
  spec.add_dependency 'zeitwerk', '~> 2.3'
28
27
 
@@ -38,7 +37,7 @@ Gem::Specification.new do |spec|
38
37
  spec.metadata = {
39
38
  'funding_uri' => 'https://karafka.io/#become-pro',
40
39
  'homepage_uri' => 'https://karafka.io',
41
- 'changelog_uri' => 'https://github.com/karafka/karafka/blob/master/CHANGELOG.md',
40
+ 'changelog_uri' => 'https://karafka.io/docs/Changelog-Karafka',
42
41
  'bug_tracker_uri' => 'https://github.com/karafka/karafka/issues',
43
42
  'source_code_uri' => 'https://github.com/karafka/karafka',
44
43
  'documentation_uri' => 'https://karafka.io/docs',
@@ -73,6 +73,7 @@ module Karafka
73
73
  # @private
74
74
  #
75
75
  # @return [Boolean] true if there was no exception, otherwise false.
76
+ #
76
77
  # @note We keep the seek offset tracking, and use it to compensate for async offset flushing
77
78
  # that may not yet kick in when error occurs. That way we pause always on the last processed
78
79
  # message.
@@ -1,31 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Karafka
4
- class Cli < Thor
4
+ class Cli
5
5
  # Base class for all the command that we want to define
6
- # This base class provides a nicer interface to Thor and allows to easier separate single
7
- # independent commands
8
- # In order to define a new command you need to:
9
- # - specify its desc
10
- # - implement call method
11
- #
12
- # @example Create a dummy command
13
- # class Dummy < Base
14
- # self.desc = 'Dummy command'
15
- #
16
- # def call
17
- # puts 'I'm doing nothing!
18
- # end
19
- # end
6
+ # This base class provides an interface to easier separate single independent commands
20
7
  class Base
21
- include Thor::Shell
8
+ # @return [Hash] given command cli options
9
+ attr_reader :options
22
10
 
23
- # We can use it to call other cli methods via this object
24
- attr_reader :cli
25
-
26
- # @param cli [Karafka::Cli] current Karafka Cli instance
27
- def initialize(cli)
28
- @cli = cli
11
+ # Creates new CLI command instance
12
+ def initialize
13
+ # Parses the given command CLI options
14
+ @options = self.class.parse_options
29
15
  end
30
16
 
31
17
  # This method should implement proper cli action
@@ -64,26 +50,46 @@ module Karafka
64
50
 
65
51
  # Allows to set description of a given cli command
66
52
  # @param desc [String] Description of a given cli command
67
- def desc(desc)
53
+ def desc(desc = nil)
68
54
  @desc ||= desc
69
55
  end
70
56
 
71
- # This method will bind a given Cli command into Karafka Cli
72
- # This method is a wrapper to way Thor defines its commands
73
- # @param cli_class [Karafka::Cli] Karafka cli_class
74
- def bind_to(cli_class)
75
- cli_class.desc name, @desc
57
+ # Allows to set aliases for a given cli command
58
+ # @param args [Array] list of aliases that we can use to run given cli command
59
+ def aliases(*args)
60
+ @aliases ||= []
61
+ @aliases << args.map(&:to_s)
62
+ end
63
+
64
+ # Parses the CLI options
65
+ # @return [Hash] hash with parsed values
66
+ def parse_options
67
+ options = {}
76
68
 
77
- (@options || []).each { |option| cli_class.option(*option) }
69
+ OptionParser.new do |opts|
70
+ (@options || []).each do |option|
71
+ # Creates aliases for backwards compatibility
72
+ names = option[3].flat_map { |name| [name, name.tr('_', '-')] }
73
+ names.map! { |name| "#{name} value1,value2,valueN" } if option[2] == Array
74
+ names.uniq!
78
75
 
79
- context = self
76
+ opts.on(
77
+ *[names, option[2], option[1]].flatten
78
+ ) { |value| options[option[0]] = value }
79
+ end
80
+ end.parse!
80
81
 
81
- cli_class.send :define_method, name do |*args|
82
- context.new(self).call(*args)
83
- end
82
+ options
84
83
  end
85
84
 
86
- private
85
+ # @return [Array<Class>] available commands
86
+ def commands
87
+ ObjectSpace
88
+ .each_object(Class)
89
+ .select { |klass| klass.superclass == Karafka::Cli::Base }
90
+ .reject { |klass| klass.to_s.end_with?('::Base') }
91
+ .sort_by(&:name)
92
+ end
87
93
 
88
94
  # @return [String] downcased current class name that we use to define name for
89
95
  # given Cli command
@@ -92,6 +98,11 @@ module Karafka
92
98
  def name
93
99
  to_s.split('::').last.downcase
94
100
  end
101
+
102
+ # @return [Array<String>] names and aliases for command matching
103
+ def names
104
+ ((@aliases || []) << name).flatten.map(&:to_s)
105
+ end
95
106
  end
96
107
  end
97
108
  end
@@ -2,11 +2,12 @@
2
2
 
3
3
  module Karafka
4
4
  # Karafka framework Cli
5
- class Cli < Thor
5
+ class Cli
6
6
  # Console Karafka Cli action
7
7
  class Console < Base
8
- desc 'Start the Karafka console (short-cut alias: "c")'
9
- option aliases: 'c'
8
+ desc 'Starts the Karafka console (short-cut alias: "c")'
9
+
10
+ aliases :c
10
11
 
11
12
  class << self
12
13
  # @return [String] Console executing command for non-Rails setup
@@ -25,7 +26,7 @@ module Karafka
25
26
 
26
27
  # Start the Karafka console
27
28
  def call
28
- cli.info
29
+ Info.new.call
29
30
 
30
31
  command = ::Karafka.rails? ? self.class.rails_console : self.class.console
31
32
 
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ # Karafka framework Cli
5
+ class Cli
6
+ # Prints info with list of commands available
7
+ class Help < Base
8
+ desc 'Describes available commands'
9
+
10
+ # Print available commands
11
+ def call
12
+ # Find the longest command for alignment purposes
13
+ max_command_length = self.class.commands.map(&:name).map(&:size).max
14
+
15
+ puts 'Karafka commands:'
16
+
17
+ # Print each command formatted with its description
18
+ self.class.commands.each do |command|
19
+ puts " #{command.name.ljust(max_command_length)} # #{command.desc}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -2,10 +2,10 @@
2
2
 
3
3
  module Karafka
4
4
  # Karafka framework Cli
5
- class Cli < Thor
5
+ class Cli
6
6
  # Info Karafka Cli action
7
7
  class Info < Base
8
- desc 'Print configuration details and other options of your application'
8
+ desc 'Prints configuration details and other options of your application'
9
9
 
10
10
  # Nice karafka banner
11
11
  BANNER = <<~BANNER
@@ -4,12 +4,12 @@ require 'erb'
4
4
 
5
5
  module Karafka
6
6
  # Karafka framework Cli
7
- class Cli < Thor
7
+ class Cli
8
8
  # Install Karafka Cli action
9
9
  class Install < Base
10
10
  include Helpers::Colorize
11
11
 
12
- desc 'Install all required things for Karafka application in current directory'
12
+ desc 'Installs all required things for Karafka application in current directory'
13
13
 
14
14
  # Directories created by default
15
15
  INSTALL_DIRS = %w[
@@ -26,9 +26,9 @@ module Karafka
26
26
  'example_consumer.rb.erb' => 'app/consumers/example_consumer.rb'
27
27
  }.freeze
28
28
 
29
- # @param args [Array] all the things that Thor CLI accepts
30
- def initialize(*args)
29
+ def initialize
31
30
  super
31
+
32
32
  dependencies = Bundler::LockfileParser.new(
33
33
  Bundler.read_file(
34
34
  Bundler.default_lockfile
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Karafka
4
4
  # Karafka framework Cli
5
- class Cli < Thor
5
+ class Cli
6
6
  # Server Karafka Cli action
7
7
  class Server < Base
8
8
  include Helpers::Colorize
@@ -12,36 +12,75 @@ module Karafka
12
12
 
13
13
  private_constant :SUPPORTED_TYPES
14
14
 
15
- desc 'Start the Karafka server (short-cut alias: "s")'
16
-
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
21
- option :consumer_groups, type: :array, default: [], aliases: :g
22
- option :subscription_groups, type: :array, default: []
23
- option :topics, type: :array, default: []
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
15
+ desc 'Starts the Karafka server (short-cut alias: "s")'
16
+
17
+ aliases :s
18
+
19
+ option(
20
+ :consumer_groups,
21
+ 'Runs server only with specified consumer groups',
22
+ Array,
23
+ %w[
24
+ -g
25
+ --consumer_groups
26
+ --include_consumer_groups
27
+ ]
28
+ )
29
+
30
+ option(
31
+ :subscription_groups,
32
+ 'Runs server only with specified subscription groups',
33
+ Array,
34
+ %w[
35
+ --subscription_groups
36
+ --include_subscription_groups
37
+ ]
38
+ )
39
+
40
+ option(
41
+ :topics,
42
+ 'Runs server only with specified topics',
43
+ Array,
44
+ %w[
45
+ --topics
46
+ --include_topics
47
+ ]
48
+ )
49
+
50
+ option(
51
+ :exclude_consumer_groups,
52
+ 'Runs server without specified consumer groups',
53
+ Array,
54
+ %w[
55
+ --exclude_consumer_groups
56
+ ]
57
+ )
58
+
59
+ option(
60
+ :exclude_subscription_groups,
61
+ 'Runs server without specified subscription groups',
62
+ Array,
63
+ %w[
64
+ --exclude_subscription_groups
65
+ ]
66
+ )
67
+
68
+ option(
69
+ :exclude_topics,
70
+ 'Runs server without specified topics',
71
+ Array,
72
+ %w[
73
+ --exclude_topics
74
+ ]
75
+ )
37
76
 
38
77
  # Start the Karafka server
39
78
  def call
40
79
  # Print our banner and info in the dev mode
41
80
  print_marketing_info if Karafka::App.env.development?
42
81
 
43
- register_inclusions(cli)
44
- register_exclusions(cli)
82
+ register_inclusions
83
+ register_exclusions
45
84
 
46
85
  Karafka::Server.run
47
86
  end
@@ -49,26 +88,22 @@ module Karafka
49
88
  private
50
89
 
51
90
  # Registers things we want to include (if defined)
52
- # @param cli [Karafka::Cli] Thor cli handler
53
- def register_inclusions(cli)
91
+ def register_inclusions
54
92
  activities = ::Karafka::App.config.internal.routing.activity_manager
55
93
 
56
94
  SUPPORTED_TYPES.each do |type|
57
- v1 = cli.options[type] || []
58
- v2 = cli.options[:"include_#{type}"] || []
59
- names = v1 + v2
95
+ names = options[type] || []
60
96
 
61
97
  names.each { |name| activities.include(type, name) }
62
98
  end
63
99
  end
64
100
 
65
101
  # Registers things we want to exclude (if defined)
66
- # @param cli [Karafka::Cli] Thor cli handler
67
- def register_exclusions(cli)
102
+ def register_exclusions
68
103
  activities = ::Karafka::App.config.internal.routing.activity_manager
69
104
 
70
105
  activities.class::SUPPORTED_TYPES.each do |type|
71
- names = cli.options[:"exclude_#{type}"] || []
106
+ names = options[:"exclude_#{type}"] || []
72
107
 
73
108
  names.each { |name| activities.exclude(type, name) }
74
109
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Karafka
4
- class Cli < Thor
4
+ class Cli
5
5
  # CLI actions related to Kafka cluster topics management
6
6
  class Topics < Base
7
7
  include Helpers::Colorize
data/lib/karafka/cli.rb CHANGED
@@ -5,31 +5,35 @@ module Karafka
5
5
  #
6
6
  # If you want to add/modify command that belongs to CLI, please review all commands
7
7
  # available in cli/ directory inside Karafka source code.
8
- #
9
- # @note Whole Cli is built using Thor
10
- # @see https://github.com/erikhuda/thor
11
- class Cli < Thor
12
- package_name 'Karafka'
13
-
8
+ class Cli
14
9
  class << self
15
- # Loads all Cli commands into Thor framework.
16
- # This method should be executed before we run Karafka::Cli.start, otherwise we won't
17
- # have any Cli commands available.
18
- def prepare
19
- cli_commands.each do |action|
20
- action.bind_to(self)
10
+ # Starts the CLI
11
+ def start
12
+ # Command we want to run, like install, server, etc
13
+ command_name = ARGV[0]
14
+ # Action for action-based commands like topics migrate
15
+ action = ARGV[1].to_s.start_with?('-') ? false : ARGV[1]
16
+
17
+ command = commands.find { |cmd| cmd.names.include?(command_name) }
18
+
19
+ if command
20
+ # Only actionable commands require command as an argument
21
+ args = action ? [action] : []
22
+
23
+ command.new.call(*args)
24
+ else
25
+ raise(
26
+ Karafka::Errors::UnrecognizedCommandError,
27
+ "Unrecognized command \"#{command_name}\""
28
+ )
21
29
  end
22
30
  end
23
31
 
24
32
  private
25
33
 
26
- # @return [Array<Class>] Array with Cli action classes that can be used as commands
27
- def cli_commands
28
- constants
29
- .map! { |object| const_get(object) }
30
- .keep_if do |object|
31
- object.instance_of?(Class) && (object < Cli::Base)
32
- end
34
+ # @return [Array<Class>] command classes
35
+ def commands
36
+ Base.commands
33
37
  end
34
38
  end
35
39
  end
@@ -43,7 +43,11 @@ module Karafka
43
43
  @closed = false
44
44
  @subscription_group = subscription_group
45
45
  @buffer = RawMessagesBuffer.new
46
- @rebalance_manager = RebalanceManager.new
46
+ @rebalance_manager = RebalanceManager.new(@subscription_group.id)
47
+ @rebalance_callback = Instrumentation::Callbacks::Rebalance.new(
48
+ @subscription_group.id,
49
+ @subscription_group.consumer_group.id
50
+ )
47
51
  @kafka = build_consumer
48
52
  # There are few operations that can happen in parallel from the listener threads as well
49
53
  # as from the workers. They are not fully thread-safe because they may be composed out of
@@ -498,7 +502,8 @@ module Karafka
498
502
  def build_consumer
499
503
  ::Rdkafka::Config.logger = ::Karafka::App.config.logger
500
504
  config = ::Rdkafka::Config.new(@subscription_group.kafka)
501
- config.consumer_rebalance_listener = @rebalance_manager
505
+ config.consumer_rebalance_listener = @rebalance_callback
506
+
502
507
  consumer = config.consumer
503
508
  @name = consumer.name
504
509
 
@@ -507,7 +512,7 @@ module Karafka
507
512
  @subscription_group.id,
508
513
  Instrumentation::Callbacks::Statistics.new(
509
514
  @subscription_group.id,
510
- @subscription_group.consumer_group_id,
515
+ @subscription_group.consumer_group.id,
511
516
  @name
512
517
  )
513
518
  )
@@ -517,7 +522,7 @@ module Karafka
517
522
  @subscription_group.id,
518
523
  Instrumentation::Callbacks::Error.new(
519
524
  @subscription_group.id,
520
- @subscription_group.consumer_group_id,
525
+ @subscription_group.consumer_group.id,
521
526
  @name
522
527
  )
523
528
  )
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Karafka
4
4
  module Connection
5
- # Manager for tracking changes in the partitions assignment.
5
+ # Manager for tracking changes in the partitions assignment after the assignment is done.
6
6
  #
7
7
  # We need tracking of those to clean up consumers that will no longer process given partitions
8
8
  # as they were taken away.
@@ -17,6 +17,10 @@ module Karafka
17
17
  #
18
18
  # @note For cooperative-sticky `#assigned_partitions` holds only the recently assigned
19
19
  # partitions, not all the partitions that are owned
20
+ #
21
+ # @note We have to have the `subscription_group` reference because we have a global pipeline
22
+ # for notifications and we need to make sure we track changes only for things that are of
23
+ # relevance to our subscription group
20
24
  class RebalanceManager
21
25
  # Empty array for internal usage not to create new objects
22
26
  EMPTY_ARRAY = [].freeze
@@ -25,12 +29,17 @@ module Karafka
25
29
 
26
30
  private_constant :EMPTY_ARRAY
27
31
 
32
+ # @param subscription_group_id [String] subscription group id
28
33
  # @return [RebalanceManager]
29
- def initialize
34
+ def initialize(subscription_group_id)
30
35
  @assigned_partitions = {}
31
36
  @revoked_partitions = {}
32
37
  @changed = false
33
38
  @active = false
39
+ @subscription_group_id = subscription_group_id
40
+
41
+ # Connects itself to the instrumentation pipeline so rebalances can be tracked
42
+ ::Karafka.monitor.subscribe(self)
34
43
  end
35
44
 
36
45
  # Resets the rebalance manager state
@@ -55,36 +64,42 @@ module Karafka
55
64
  @active
56
65
  end
57
66
 
58
- # Callback that kicks in inside of rdkafka, when new partitions are assigned.
67
+ # We consider as lost only partitions that were taken away and not re-assigned back to us
68
+ def lost_partitions
69
+ lost_partitions = {}
70
+
71
+ revoked_partitions.each do |topic, partitions|
72
+ lost_partitions[topic] = partitions - assigned_partitions.fetch(topic, EMPTY_ARRAY)
73
+ end
74
+
75
+ lost_partitions
76
+ end
77
+
78
+ # Callback that kicks in inside of rdkafka, when new partitions were assigned.
59
79
  #
60
80
  # @private
61
- # @param partitions [Rdkafka::Consumer::TopicPartitionList]
62
- def on_partitions_assigned(partitions)
81
+ # @param event [Karafka::Core::Monitoring::Event]
82
+ def on_rebalance_partitions_assigned(event)
83
+ # Apply changes only for our subscription group
84
+ return unless event[:subscription_group_id] == @subscription_group_id
85
+
63
86
  @active = true
64
- @assigned_partitions = partitions.to_h.transform_values { |part| part.map(&:partition) }
87
+ @assigned_partitions = event[:tpl].to_h.transform_values { |part| part.map(&:partition) }
65
88
  @changed = true
66
89
  end
67
90
 
68
- # Callback that kicks in inside of rdkafka, when partitions are revoked.
91
+ # Callback that kicks in inside of rdkafka, when partitions were revoked.
69
92
  #
70
93
  # @private
71
- # @param partitions [Rdkafka::Consumer::TopicPartitionList]
72
- def on_partitions_revoked(partitions)
94
+ # @param event [Karafka::Core::Monitoring::Event]
95
+ def on_rebalance_partitions_revoked(event)
96
+ # Apply changes only for our subscription group
97
+ return unless event[:subscription_group_id] == @subscription_group_id
98
+
73
99
  @active = true
74
- @revoked_partitions = partitions.to_h.transform_values { |part| part.map(&:partition) }
100
+ @revoked_partitions = event[:tpl].to_h.transform_values { |part| part.map(&:partition) }
75
101
  @changed = true
76
102
  end
77
-
78
- # We consider as lost only partitions that were taken away and not re-assigned back to us
79
- def lost_partitions
80
- lost_partitions = {}
81
-
82
- revoked_partitions.each do |topic, partitions|
83
- lost_partitions[topic] = partitions - assigned_partitions.fetch(topic, EMPTY_ARRAY)
84
- end
85
-
86
- lost_partitions
87
- end
88
103
  end
89
104
  end
90
105
  end