karafka 2.2.7 → 2.2.8.beta1

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.
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