karafka 2.2.12 → 2.2.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +141 -121
  4. data/Gemfile.lock +10 -10
  5. data/config/locales/errors.yml +2 -1
  6. data/docker-compose.yml +2 -0
  7. data/lib/karafka/admin.rb +109 -3
  8. data/lib/karafka/app.rb +7 -0
  9. data/lib/karafka/base_consumer.rb +23 -30
  10. data/lib/karafka/connection/client.rb +13 -10
  11. data/lib/karafka/connection/consumer_group_coordinator.rb +3 -3
  12. data/lib/karafka/connection/listener.rb +18 -10
  13. data/lib/karafka/connection/listeners_batch.rb +6 -1
  14. data/lib/karafka/contracts/config.rb +2 -1
  15. data/lib/karafka/instrumentation/assignments_tracker.rb +96 -0
  16. data/lib/karafka/instrumentation/callbacks/rebalance.rb +10 -7
  17. data/lib/karafka/instrumentation/logger_listener.rb +0 -9
  18. data/lib/karafka/instrumentation/notifications.rb +6 -3
  19. data/lib/karafka/instrumentation/vendors/datadog/logger_listener.rb +2 -2
  20. data/lib/karafka/pro/instrumentation/performance_tracker.rb +85 -0
  21. data/lib/karafka/pro/loader.rb +3 -2
  22. data/lib/karafka/pro/processing/coordinator.rb +12 -6
  23. data/lib/karafka/pro/processing/jobs_queue.rb +109 -0
  24. data/lib/karafka/pro/processing/schedulers/base.rb +127 -0
  25. data/lib/karafka/pro/processing/schedulers/default.rb +109 -0
  26. data/lib/karafka/pro/processing/strategies/aj/lrj_mom_vp.rb +1 -1
  27. data/lib/karafka/pro/processing/strategies/default.rb +3 -1
  28. data/lib/karafka/pro/processing/strategies/lrj/default.rb +10 -1
  29. data/lib/karafka/pro/processing/strategies/lrj/mom.rb +1 -1
  30. data/lib/karafka/pro/processing/strategies/vp/default.rb +9 -5
  31. data/lib/karafka/processing/coordinator.rb +13 -7
  32. data/lib/karafka/processing/executor.rb +27 -3
  33. data/lib/karafka/processing/executors_buffer.rb +3 -3
  34. data/lib/karafka/processing/jobs/base.rb +19 -2
  35. data/lib/karafka/processing/jobs/consume.rb +3 -3
  36. data/lib/karafka/processing/jobs/idle.rb +5 -0
  37. data/lib/karafka/processing/jobs/revoked.rb +5 -0
  38. data/lib/karafka/processing/jobs/shutdown.rb +5 -0
  39. data/lib/karafka/processing/jobs_queue.rb +45 -17
  40. data/lib/karafka/processing/schedulers/default.rb +41 -0
  41. data/lib/karafka/processing/strategies/base.rb +13 -4
  42. data/lib/karafka/processing/strategies/default.rb +17 -5
  43. data/lib/karafka/processing/worker.rb +4 -1
  44. data/lib/karafka/routing/builder.rb +32 -17
  45. data/lib/karafka/routing/proxy.rb +4 -3
  46. data/lib/karafka/routing/subscription_group.rb +11 -6
  47. data/lib/karafka/routing/topics.rb +1 -1
  48. data/lib/karafka/runner.rb +1 -1
  49. data/lib/karafka/setup/config.rb +5 -1
  50. data/lib/karafka/version.rb +1 -1
  51. data/lib/karafka.rb +0 -1
  52. data.tar.gz.sig +0 -0
  53. metadata +8 -5
  54. metadata.gz.sig +0 -0
  55. data/lib/karafka/pro/performance_tracker.rb +0 -84
  56. data/lib/karafka/pro/processing/scheduler.rb +0 -75
  57. data/lib/karafka/processing/scheduler.rb +0 -22
data/lib/karafka/admin.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Karafka
4
- # Simple admin actions that we can perform via Karafka on our Kafka cluster
4
+ # Admin actions that we can perform via Karafka on our Kafka cluster
5
5
  #
6
6
  # @note It always initializes a new admin instance as we want to ensure it is always closed
7
7
  # Since admin actions are not performed that often, that should be ok.
@@ -137,6 +137,109 @@ module Karafka
137
137
  end
138
138
  end
139
139
 
140
+ # Moves the offset on a given consumer group and provided topic to the requested location
141
+ #
142
+ # @param consumer_group_id [String] id of the consumer group for which we want to move the
143
+ # existing offset
144
+ # @param topics_with_partitions_and_offsets [Hash] Hash with list of topics and settings to
145
+ # where to move given consumer. It allows us to move particular partitions or whole topics
146
+ # if we want to reset all partitions to for example a point in time.
147
+ #
148
+ # @note This method should **not** be executed on a running consumer group as it creates a
149
+ # "fake" consumer and uses it to move offsets.
150
+ #
151
+ # @example Move a single topic partition nr 1 offset to 100
152
+ # Karafka::Admin.seek_consumer_group('group-id', { 'topic' => { 1 => 100 } })
153
+ #
154
+ # @example Move offsets on all partitions of a topic to 100
155
+ # Karafka::Admin.seek_consumer_group('group-id', { 'topic' => 100 })
156
+ #
157
+ # @example Move offset to 5 seconds ago on partition 2
158
+ # Karafka::Admin.seek_consumer_group('group-id', { 'topic' => { 2 => 5.seconds.ago } })
159
+ def seek_consumer_group(consumer_group_id, topics_with_partitions_and_offsets)
160
+ tpl_base = {}
161
+
162
+ # Normalize the data so we always have all partitions and topics in the same format
163
+ # That is in a format where we have topics and all partitions with their per partition
164
+ # assigned offsets
165
+ topics_with_partitions_and_offsets.each do |topic, partitions_with_offsets|
166
+ tpl_base[topic] = {}
167
+
168
+ if partitions_with_offsets.is_a?(Hash)
169
+ tpl_base[topic] = partitions_with_offsets
170
+ else
171
+ topic(topic)[:partition_count].times do |partition|
172
+ tpl_base[topic][partition] = partitions_with_offsets
173
+ end
174
+ end
175
+ end
176
+
177
+ tpl = Rdkafka::Consumer::TopicPartitionList.new
178
+ # In case of time based location, we need to to a pre-resolution, that's why we keep it
179
+ # separately
180
+ time_tpl = Rdkafka::Consumer::TopicPartitionList.new
181
+
182
+ # Distribute properly the offset type
183
+ tpl_base.each do |topic, partitions_with_offsets|
184
+ partitions_with_offsets.each do |partition, offset|
185
+ target = offset.is_a?(Time) ? time_tpl : tpl
186
+ target.add_topic_and_partitions_with_offsets(topic, [[partition, offset]])
187
+ end
188
+ end
189
+
190
+ # We set this that way so we can impersonate this consumer group and seek where we want
191
+ mapped_consumer_group_id = app_config.consumer_mapper.call(consumer_group_id)
192
+ settings = { 'group.id': mapped_consumer_group_id }
193
+
194
+ with_consumer(settings) do |consumer|
195
+ # If we have any time based stuff to resolve, we need to do it prior to commits
196
+ unless time_tpl.empty?
197
+ real_offsets = consumer.offsets_for_times(time_tpl)
198
+
199
+ real_offsets.to_h.each do |name, results|
200
+ results.each do |result|
201
+ raise(Errors::InvalidTimeBasedOffsetError) unless result
202
+
203
+ partition = result.partition
204
+
205
+ # Negative offset means we're beyond last message and we need to query for the
206
+ # high watermark offset to get the most recent offset and move there
207
+ if result.offset.negative?
208
+ _, offset = consumer.query_watermark_offsets(name, result.partition)
209
+ else
210
+ # If we get an offset, it means there existed a message close to this time
211
+ # location
212
+ offset = result.offset
213
+ end
214
+
215
+ # Since now we have proper offsets, we can add this to the final tpl for commit
216
+ tpl.add_topic_and_partitions_with_offsets(name, [[partition, offset]])
217
+ end
218
+ end
219
+ end
220
+
221
+ consumer.commit(tpl, false)
222
+ end
223
+ end
224
+
225
+ # Removes given consumer group (if exists)
226
+ #
227
+ # @param consumer_group_id [String] consumer group name without the mapper name (if any used)
228
+ #
229
+ # @note Please note, Karafka will apply the consumer group mapper on the provided consumer
230
+ # group.
231
+ #
232
+ # @note This method should not be used on a running consumer group as it will not yield any
233
+ # results.
234
+ def delete_consumer_group(consumer_group_id)
235
+ mapped_consumer_group_id = app_config.consumer_mapper.call(consumer_group_id)
236
+
237
+ with_admin do |admin|
238
+ handler = admin.delete_group(mapped_consumer_group_id)
239
+ handler.wait(max_wait_timeout: app_config.admin.max_wait_time)
240
+ end
241
+ end
242
+
140
243
  # Fetches the watermark offsets for a given topic partition
141
244
  #
142
245
  # @param name [String, Symbol] topic name
@@ -264,7 +367,7 @@ module Karafka
264
367
  # @param settings [Hash] extra settings for config (if needed)
265
368
  # @return [::Rdkafka::Config] rdkafka config
266
369
  def config(type, settings)
267
- group_id = app_config.consumer_mapper.call(
370
+ mapped_admin_group_id = app_config.consumer_mapper.call(
268
371
  app_config.admin.group_id
269
372
  )
270
373
 
@@ -272,8 +375,11 @@ module Karafka
272
375
  .kafka
273
376
  .then(&:dup)
274
377
  .merge(app_config.admin.kafka)
378
+ .tap { |config| config[:'group.id'] = mapped_admin_group_id }
379
+ # We merge after setting the group id so it can be altered if needed
380
+ # In general in admin we only should alter it when we need to impersonate a given
381
+ # consumer group or do something similar
275
382
  .merge!(settings)
276
- .tap { |config| config[:'group.id'] = group_id }
277
383
  .then { |config| Karafka::Setup::AttributesMap.public_send(type, config) }
278
384
  .then { |config| ::Rdkafka::Config.new(config) }
279
385
  end
data/lib/karafka/app.rb CHANGED
@@ -36,6 +36,13 @@ module Karafka
36
36
  # Just a nicer name for the consumer groups
37
37
  alias routes consumer_groups
38
38
 
39
+ # Returns current assignments of this process. Both topics and partitions
40
+ #
41
+ # @return [Hash<Karafka::Routing::Topic, Array<Integer>>]
42
+ def assignments
43
+ Instrumentation::AssignmentsTracker.instance.current
44
+ end
45
+
39
46
  # Allow for easier status management via `Karafka::App` by aliasing status methods here
40
47
  Status::STATES.each do |state, transition|
41
48
  class_eval <<~RUBY, __FILE__, __LINE__ + 1
@@ -34,16 +34,9 @@ module Karafka
34
34
  # @note This should not be used by the end users as it is part of the lifecycle of things and
35
35
  # not as a part of the public api. This should not perform any extensive operations as it is
36
36
  # blocking and running in the listener thread.
37
- def on_before_enqueue
37
+ def on_before_schedule_consume
38
38
  @used = true
39
- handle_before_enqueue
40
- rescue StandardError => e
41
- Karafka.monitor.instrument(
42
- 'error.occurred',
43
- error: e,
44
- caller: self,
45
- type: 'consumer.before_enqueue.error'
46
- )
39
+ handle_before_schedule_consume
47
40
  end
48
41
 
49
42
  # Can be used to run preparation code in the worker
@@ -59,13 +52,6 @@ module Karafka
59
52
  # We run this after the full metadata setup, so we can use all the messages information
60
53
  # if needed
61
54
  handle_before_consume
62
- rescue StandardError => e
63
- Karafka.monitor.instrument(
64
- 'error.occurred',
65
- error: e,
66
- caller: self,
67
- type: 'consumer.before_consume.error'
68
- )
69
55
  end
70
56
 
71
57
  # Executes the default consumer flow.
@@ -94,13 +80,13 @@ module Karafka
94
80
  # not as part of the public api.
95
81
  def on_after_consume
96
82
  handle_after_consume
97
- rescue StandardError => e
98
- Karafka.monitor.instrument(
99
- 'error.occurred',
100
- error: e,
101
- caller: self,
102
- type: 'consumer.after_consume.error'
103
- )
83
+ end
84
+
85
+ # Can be used to run code prior to scheduling of idle execution
86
+ #
87
+ # @private
88
+ def on_before_schedule_idle
89
+ handle_before_schedule_idle
104
90
  end
105
91
 
106
92
  # Trigger method for running on idle runs without messages
@@ -108,13 +94,13 @@ module Karafka
108
94
  # @private
109
95
  def on_idle
110
96
  handle_idle
111
- rescue StandardError => e
112
- Karafka.monitor.instrument(
113
- 'error.occurred',
114
- error: e,
115
- caller: self,
116
- type: 'consumer.idle.error'
117
- )
97
+ end
98
+
99
+ # Can be used to run code prior to scheduling of revoked execution
100
+ #
101
+ # @private
102
+ def on_before_schedule_revoked
103
+ handle_before_schedule_revoked
118
104
  end
119
105
 
120
106
  # Trigger method for running on partition revocation.
@@ -131,6 +117,13 @@ module Karafka
131
117
  )
132
118
  end
133
119
 
120
+ # Can be used to run code prior to scheduling of revoked execution
121
+ #
122
+ # @private
123
+ def on_before_schedule_shutdown
124
+ handle_before_schedule_shutdown
125
+ end
126
+
134
127
  # Trigger method for running on shutdown.
135
128
  #
136
129
  # @private
@@ -45,10 +45,7 @@ module Karafka
45
45
  @buffer = RawMessagesBuffer.new
46
46
  @tick_interval = ::Karafka::App.config.internal.tick_interval
47
47
  @rebalance_manager = RebalanceManager.new(@subscription_group.id)
48
- @rebalance_callback = Instrumentation::Callbacks::Rebalance.new(
49
- @subscription_group.id,
50
- @subscription_group.consumer_group.id
51
- )
48
+ @rebalance_callback = Instrumentation::Callbacks::Rebalance.new(@subscription_group)
52
49
  @events_poller = Helpers::IntervalRunner.new { events_poll }
53
50
  @kafka = build_consumer
54
51
  # There are few operations that can happen in parallel from the listener threads as well
@@ -309,12 +306,18 @@ module Karafka
309
306
 
310
307
  # Closes and resets the client completely.
311
308
  def reset
312
- close
313
-
314
- @events_poller.reset
315
- @closed = false
316
- @paused_tpls.clear
317
- @kafka = build_consumer
309
+ Karafka.monitor.instrument(
310
+ 'client.reset',
311
+ caller: self,
312
+ subscription_group: @subscription_group
313
+ ) do
314
+ close
315
+
316
+ @events_poller.reset
317
+ @closed = false
318
+ @paused_tpls.clear
319
+ @kafka = build_consumer
320
+ end
318
321
  end
319
322
 
320
323
  # Runs a single poll on the main queue and consumer queue ignoring all the potential errors
@@ -16,7 +16,7 @@ module Karafka
16
16
  class ConsumerGroupCoordinator
17
17
  # @param group_size [Integer] number of separate subscription groups in a consumer group
18
18
  def initialize(group_size)
19
- @shutdown_lock = Mutex.new
19
+ @shutdown_mutex = Mutex.new
20
20
  @group_size = group_size
21
21
  @finished = Set.new
22
22
  end
@@ -30,12 +30,12 @@ module Karafka
30
30
  # @return [Boolean] can we start shutdown on a given listener
31
31
  # @note If true, will also obtain a lock so no-one else will be closing the same time we do
32
32
  def shutdown?
33
- finished? && @shutdown_lock.try_lock
33
+ finished? && @shutdown_mutex.try_lock
34
34
  end
35
35
 
36
36
  # Unlocks the shutdown lock
37
37
  def unlock
38
- @shutdown_lock.unlock if @shutdown_lock.owned?
38
+ @shutdown_mutex.unlock if @shutdown_mutex.owned?
39
39
  end
40
40
 
41
41
  # Marks given listener as finished
@@ -23,8 +23,9 @@ module Karafka
23
23
  # @param consumer_group_coordinator [Karafka::Connection::ConsumerGroupCoordinator]
24
24
  # @param subscription_group [Karafka::Routing::SubscriptionGroup]
25
25
  # @param jobs_queue [Karafka::Processing::JobsQueue] queue where we should push work
26
+ # @param scheduler [Karafka::Processing::Scheduler] scheduler we want to use
26
27
  # @return [Karafka::Connection::Listener] listener instance
27
- def initialize(consumer_group_coordinator, subscription_group, jobs_queue)
28
+ def initialize(consumer_group_coordinator, subscription_group, jobs_queue, scheduler)
28
29
  proc_config = ::Karafka::App.config.internal.processing
29
30
 
30
31
  @id = SecureRandom.hex(6)
@@ -36,8 +37,7 @@ module Karafka
36
37
  @executors = Processing::ExecutorsBuffer.new(@client, subscription_group)
37
38
  @jobs_builder = proc_config.jobs_builder
38
39
  @partitioner = proc_config.partitioner_class.new(subscription_group)
39
- # We reference scheduler here as it is much faster than fetching this each time
40
- @scheduler = proc_config.scheduler
40
+ @scheduler = scheduler
41
41
  @events_poller = Helpers::IntervalRunner.new { @client.events_poll }
42
42
  # We keep one buffer for messages to preserve memory and not allocate extra objects
43
43
  # We can do this that way because we always first schedule jobs using messages before we
@@ -45,6 +45,8 @@ module Karafka
45
45
  @messages_buffer = MessagesBuffer.new(subscription_group)
46
46
  @mutex = Mutex.new
47
47
  @stopped = false
48
+
49
+ @jobs_queue.register(@subscription_group.id)
48
50
  end
49
51
 
50
52
  # Runs the main listener fetch loop.
@@ -230,7 +232,7 @@ module Karafka
230
232
  # here. In cases like this, we do not run a revocation job
231
233
  @executors.find_all(topic, partition).each do |executor|
232
234
  job = @jobs_builder.revoked(executor)
233
- job.before_enqueue
235
+ job.before_schedule
234
236
  jobs << job
235
237
  end
236
238
 
@@ -243,7 +245,7 @@ module Karafka
243
245
  end
244
246
  end
245
247
 
246
- @scheduler.schedule_revocation(@jobs_queue, jobs)
248
+ @scheduler.on_schedule_revocation(jobs)
247
249
  end
248
250
 
249
251
  # Enqueues the shutdown jobs for all the executors that exist in our subscription group
@@ -252,11 +254,11 @@ module Karafka
252
254
 
253
255
  @executors.each do |executor|
254
256
  job = @jobs_builder.shutdown(executor)
255
- job.before_enqueue
257
+ job.before_schedule
256
258
  jobs << job
257
259
  end
258
260
 
259
- @scheduler.schedule_shutdown(@jobs_queue, jobs)
261
+ @scheduler.on_schedule_shutdown(jobs)
260
262
  end
261
263
 
262
264
  # Polls messages within the time and amount boundaries defined in the settings and then
@@ -296,14 +298,17 @@ module Karafka
296
298
  end
297
299
  end
298
300
 
299
- jobs.each(&:before_enqueue)
301
+ jobs.each(&:before_schedule)
300
302
 
301
- @scheduler.schedule_consumption(@jobs_queue, jobs)
303
+ @scheduler.on_schedule_consumption(jobs)
302
304
  end
303
305
 
304
306
  # Waits for all the jobs from a given subscription group to finish before moving forward
305
307
  def wait
306
- @jobs_queue.wait(@subscription_group.id) { @events_poller.call }
308
+ @jobs_queue.wait(@subscription_group.id) do
309
+ @events_poller.call
310
+ @scheduler.on_manage
311
+ end
307
312
  end
308
313
 
309
314
  # Waits without blocking the polling
@@ -319,6 +324,8 @@ module Karafka
319
324
  def wait_pinging(wait_until:, after_ping: -> {})
320
325
  until wait_until.call
321
326
  @client.ping
327
+ @scheduler.on_manage
328
+
322
329
  after_ping.call
323
330
  sleep(0.2)
324
331
  end
@@ -334,6 +341,7 @@ module Karafka
334
341
  # resetting.
335
342
  @jobs_queue.wait(@subscription_group.id)
336
343
  @jobs_queue.clear(@subscription_group.id)
344
+ @scheduler.on_clear(@subscription_group.id)
337
345
  @events_poller.reset
338
346
  @client.reset
339
347
  @coordinators.reset
@@ -11,6 +11,10 @@ module Karafka
11
11
  # @param jobs_queue [JobsQueue]
12
12
  # @return [ListenersBatch]
13
13
  def initialize(jobs_queue)
14
+ # We need one scheduler for all the listeners because in case of complex schedulers, they
15
+ # should be able to distribute work whenever any work is done in any of the listeners
16
+ scheduler = App.config.internal.processing.scheduler_class.new(jobs_queue)
17
+
14
18
  @coordinators = []
15
19
 
16
20
  @batch = App.subscription_groups.flat_map do |_consumer_group, subscription_groups|
@@ -24,7 +28,8 @@ module Karafka
24
28
  Connection::Listener.new(
25
29
  consumer_group_coordinator,
26
30
  subscription_group,
27
- jobs_queue
31
+ jobs_queue,
32
+ scheduler
28
33
  )
29
34
  end
30
35
  end
@@ -73,7 +73,8 @@ module Karafka
73
73
 
74
74
  nested(:processing) do
75
75
  required(:jobs_builder) { |val| !val.nil? }
76
- required(:scheduler) { |val| !val.nil? }
76
+ required(:jobs_queue_class) { |val| !val.nil? }
77
+ required(:scheduler_class) { |val| !val.nil? }
77
78
  required(:coordinator_class) { |val| !val.nil? }
78
79
  required(:partitioner_class) { |val| !val.nil? }
79
80
  required(:strategy_selector) { |val| !val.nil? }
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Karafka
4
+ module Instrumentation
5
+ # Keeps track of active assignments and materializes them by returning the routing topics
6
+ # with appropriate partitions that are assigned at a given moment
7
+ #
8
+ # It is auto-subscribed as part of Karafka itself.
9
+ #
10
+ # It is not heavy from the computational point of view, as it only operates during rebalances.
11
+ #
12
+ # We keep assignments as flat topics structure because we can go from topics to both
13
+ # subscription and consumer groups if needed.
14
+ class AssignmentsTracker
15
+ include Singleton
16
+
17
+ def initialize
18
+ @mutex = Mutex.new
19
+ @assignments = Hash.new { |hash, key| hash[key] = [] }
20
+ end
21
+
22
+ # Returns all the active/current assignments of this given process
23
+ #
24
+ # @return [Hash<Karafka::Routing::Topic, Array<Integer>>]
25
+ #
26
+ # @note Keep in mind, that those assignments can change any time, especially when working
27
+ # with multiple consumer groups or subscription groups.
28
+ #
29
+ # @note We return a copy because we modify internals and we do not want user to tamper with
30
+ # the data accidentally
31
+ def current
32
+ assignments = {}
33
+
34
+ @assignments.each do |topic, partitions|
35
+ assignments[topic] = partitions.dup.freeze
36
+ end
37
+
38
+ assignments.freeze
39
+ end
40
+
41
+ # Clears all the assignments
42
+ def clear
43
+ @mutex.synchronize do
44
+ @assignments.clear
45
+ end
46
+ end
47
+
48
+ # When client is under reset due to critical issues, remove all of its assignments as we will
49
+ # get a new set of assignments
50
+ # @param event [Karafka::Core::Monitoring::Event]
51
+ def on_client_reset(event)
52
+ sg = event[:subscription_group]
53
+
54
+ @mutex.synchronize do
55
+ @assignments.delete_if do |topic, _partitions|
56
+ topic.subscription_group.id == sg.id
57
+ end
58
+ end
59
+ end
60
+
61
+ # Removes partitions from the current assignments hash
62
+ #
63
+ # @param event [Karafka::Core::Monitoring::Event]
64
+ def on_rebalance_partitions_revoked(event)
65
+ sg = event[:subscription_group]
66
+
67
+ @mutex.synchronize do
68
+ event[:tpl].to_h.each do |topic, partitions|
69
+ topic = sg.topics.find(topic)
70
+
71
+ @assignments[topic] -= partitions.map(&:partition)
72
+ @assignments[topic].sort!
73
+ # Remove completely topics for which we do not have any assignments left
74
+ @assignments.delete_if { |_topic, cur_partitions| cur_partitions.empty? }
75
+ end
76
+ end
77
+ end
78
+
79
+ # # Adds partitions to the current assignments hash
80
+ #
81
+ # @param event [Karafka::Core::Monitoring::Event]
82
+ def on_rebalance_partitions_assigned(event)
83
+ sg = event[:subscription_group]
84
+
85
+ @mutex.synchronize do
86
+ event[:tpl].to_h.each do |topic, partitions|
87
+ topic = sg.topics.find(topic)
88
+
89
+ @assignments[topic] += partitions.map(&:partition)
90
+ @assignments[topic].sort!
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -6,11 +6,10 @@ module Karafka
6
6
  # Callback that connects to the librdkafka rebalance callback and converts those events into
7
7
  # our internal events
8
8
  class Rebalance
9
- # @param subscription_group_id [String] id of the current subscription group instance
10
- # @param consumer_group_id [String] id of the current consumer group
11
- def initialize(subscription_group_id, consumer_group_id)
12
- @subscription_group_id = subscription_group_id
13
- @consumer_group_id = consumer_group_id
9
+ # @param subscription_group [Karafka::Routes::SubscriptionGroup] subscription group for
10
+ # which we want to manage rebalances
11
+ def initialize(subscription_group)
12
+ @subscription_group = subscription_group
14
13
  end
15
14
 
16
15
  # Publishes an event that partitions are going to be revoked.
@@ -53,8 +52,12 @@ module Karafka
53
52
  ::Karafka.monitor.instrument(
54
53
  "rebalance.#{name}",
55
54
  caller: self,
56
- subscription_group_id: @subscription_group_id,
57
- consumer_group_id: @consumer_group_id,
55
+ # We keep the id references here for backwards compatibility as some of the monitors
56
+ # may use the id references
57
+ subscription_group_id: @subscription_group.id,
58
+ subscription_group: @subscription_group,
59
+ consumer_group_id: @subscription_group.consumer_group.id,
60
+ consumer_group: @subscription_group.consumer_group,
58
61
  tpl: tpl
59
62
  )
60
63
  end
@@ -241,15 +241,6 @@ module Karafka
241
241
  when 'consumer.revoked.error'
242
242
  error "Consumer on revoked failed due to an error: #{error}"
243
243
  error details
244
- when 'consumer.before_enqueue.error'
245
- error "Consumer before enqueue failed due to an error: #{error}"
246
- error details
247
- when 'consumer.before_consume.error'
248
- error "Consumer before consume failed due to an error: #{error}"
249
- error details
250
- when 'consumer.after_consume.error'
251
- error "Consumer after consume failed due to an error: #{error}"
252
- error details
253
244
  when 'consumer.idle.error'
254
245
  error "Consumer idle failed due to an error: #{error}"
255
246
  error details
@@ -20,6 +20,7 @@ module Karafka
20
20
  active_job.consume
21
21
  active_job.consumed
22
22
 
23
+ app.initializing
23
24
  app.initialized
24
25
  app.running
25
26
  app.quieting
@@ -30,26 +31,28 @@ module Karafka
30
31
 
31
32
  client.pause
32
33
  client.resume
34
+ client.reset
33
35
 
34
36
  connection.listener.before_fetch_loop
35
37
  connection.listener.fetch_loop
36
38
  connection.listener.fetch_loop.received
37
39
 
38
- connection.client.poll.error
39
- connection.client.unsubscribe.error
40
-
41
40
  rebalance.partitions_assign
42
41
  rebalance.partitions_assigned
43
42
  rebalance.partitions_revoke
44
43
  rebalance.partitions_revoked
45
44
 
45
+ consumer.before_schedule_consume
46
46
  consumer.consume
47
47
  consumer.consumed
48
48
  consumer.consuming.pause
49
49
  consumer.consuming.retry
50
+ consumer.before_schedule_idle
50
51
  consumer.idle
52
+ consumer.before_schedule_revoked
51
53
  consumer.revoke
52
54
  consumer.revoked
55
+ consumer.before_schedule_shutdown
53
56
  consumer.shutting_down
54
57
  consumer.shutdown
55
58
 
@@ -94,8 +94,8 @@ module Karafka
94
94
  error "Consumer consuming error: #{error}"
95
95
  when 'consumer.revoked.error'
96
96
  error "Consumer on revoked failed due to an error: #{error}"
97
- when 'consumer.before_enqueue.error'
98
- error "Consumer before enqueue failed due to an error: #{error}"
97
+ when 'consumer.before_schedule.error'
98
+ error "Consumer before schedule failed due to an error: #{error}"
99
99
  when 'consumer.before_consume.error'
100
100
  error "Consumer before consume failed due to an error: #{error}"
101
101
  when 'consumer.after_consume.error'