karafka 2.0.0 → 2.1.0
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/ci.yml +40 -16
- data/.rspec +4 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +459 -796
- data/Gemfile +3 -2
- data/Gemfile.lock +44 -32
- data/LICENSE +1 -1
- data/README.md +22 -17
- data/bin/integrations +86 -26
- data/bin/karafka +1 -13
- data/bin/rspecs +6 -0
- data/bin/verify_license_integrity +37 -0
- data/certs/cert_chain.pem +26 -0
- data/config/{errors.yml → locales/errors.yml} +34 -6
- data/config/locales/pro_errors.yml +34 -0
- data/docker-compose.yml +4 -30
- data/karafka.gemspec +17 -10
- data/lib/active_job/karafka.rb +3 -7
- data/lib/active_job/queue_adapters/karafka_adapter.rb +7 -1
- data/lib/karafka/active_job/consumer.rb +29 -6
- data/lib/karafka/active_job/current_attributes/loading.rb +36 -0
- data/lib/karafka/active_job/current_attributes/persistence.rb +28 -0
- data/lib/karafka/active_job/current_attributes.rb +42 -0
- data/lib/karafka/active_job/dispatcher.rb +34 -3
- data/lib/karafka/active_job/job_options_contract.rb +13 -2
- data/lib/karafka/admin.rb +246 -0
- data/lib/karafka/app.rb +30 -7
- data/lib/karafka/base_consumer.rb +124 -82
- data/lib/karafka/cli/base.rb +20 -0
- data/lib/karafka/cli/console.rb +13 -8
- data/lib/karafka/cli/info.rb +3 -2
- data/lib/karafka/cli/server.rb +55 -8
- data/lib/karafka/cli/topics.rb +146 -0
- data/lib/karafka/connection/client.rb +118 -61
- data/lib/karafka/connection/consumer_group_coordinator.rb +48 -0
- data/lib/karafka/connection/listener.rb +78 -30
- data/lib/karafka/connection/listeners_batch.rb +18 -2
- data/lib/karafka/connection/rebalance_manager.rb +3 -0
- data/lib/karafka/contracts/config.rb +1 -1
- data/lib/karafka/contracts/consumer_group.rb +22 -9
- data/lib/karafka/contracts/server_cli_options.rb +71 -11
- data/lib/karafka/contracts/topic.rb +65 -0
- data/lib/karafka/contracts.rb +1 -1
- data/lib/karafka/embedded.rb +36 -0
- data/lib/karafka/errors.rb +6 -4
- data/lib/karafka/helpers/colorize.rb +6 -0
- data/lib/karafka/instrumentation/callbacks/error.rb +3 -4
- data/lib/karafka/instrumentation/callbacks/statistics.rb +14 -4
- data/lib/karafka/instrumentation/logger_listener.rb +151 -22
- data/lib/karafka/instrumentation/notifications.rb +26 -7
- data/lib/karafka/instrumentation/proctitle_listener.rb +7 -16
- data/lib/karafka/instrumentation/vendors/datadog/dashboard.json +1 -1
- data/lib/karafka/instrumentation/vendors/datadog/logger_listener.rb +153 -0
- data/lib/karafka/instrumentation/vendors/datadog/{listener.rb → metrics_listener.rb} +62 -35
- data/lib/karafka/instrumentation/vendors/kubernetes/liveness_listener.rb +166 -0
- data/lib/karafka/licenser.rb +53 -50
- data/lib/karafka/messages/builders/batch_metadata.rb +8 -8
- data/lib/karafka/messages/builders/messages.rb +6 -2
- data/lib/karafka/messages/message.rb +14 -2
- data/lib/karafka/messages/messages.rb +5 -0
- data/lib/karafka/messages/parser.rb +14 -0
- data/lib/karafka/patches/rdkafka/bindings.rb +132 -0
- data/lib/karafka/pro/active_job/consumer.rb +10 -9
- data/lib/karafka/pro/active_job/dispatcher.rb +28 -3
- data/lib/karafka/pro/active_job/job_options_contract.rb +16 -3
- data/lib/karafka/pro/encryption/cipher.rb +58 -0
- data/lib/karafka/pro/encryption/contracts/config.rb +79 -0
- data/lib/karafka/pro/encryption/errors.rb +24 -0
- data/lib/karafka/pro/encryption/messages/middleware.rb +46 -0
- data/lib/karafka/pro/encryption/messages/parser.rb +56 -0
- data/lib/karafka/pro/encryption/setup/config.rb +48 -0
- data/lib/karafka/pro/encryption.rb +47 -0
- data/lib/karafka/pro/iterator.rb +253 -0
- data/lib/karafka/pro/loader.rb +52 -26
- data/lib/karafka/pro/performance_tracker.rb +10 -6
- data/lib/karafka/pro/processing/collapser.rb +62 -0
- data/lib/karafka/pro/processing/coordinator.rb +92 -16
- data/lib/karafka/pro/processing/filters/base.rb +61 -0
- data/lib/karafka/pro/processing/filters/delayer.rb +70 -0
- data/lib/karafka/pro/processing/filters/expirer.rb +51 -0
- data/lib/karafka/pro/processing/filters/throttler.rb +84 -0
- data/lib/karafka/pro/processing/filters/virtual_limiter.rb +52 -0
- data/lib/karafka/pro/processing/filters_applier.rb +104 -0
- data/lib/karafka/pro/processing/jobs/consume_non_blocking.rb +7 -5
- data/lib/karafka/pro/processing/jobs/revoked_non_blocking.rb +37 -0
- data/lib/karafka/pro/processing/jobs_builder.rb +22 -4
- data/lib/karafka/pro/processing/partitioner.rb +33 -24
- data/lib/karafka/pro/processing/scheduler.rb +27 -8
- data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_lrj_mom.rb +68 -0
- data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_lrj_mom_vp.rb +74 -0
- data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_mom.rb +72 -0
- data/lib/karafka/pro/processing/strategies/aj/dlq_ftr_mom_vp.rb +76 -0
- data/lib/karafka/pro/processing/strategies/aj/dlq_lrj_mom.rb +64 -0
- data/lib/karafka/pro/processing/strategies/aj/dlq_lrj_mom_vp.rb +68 -0
- data/lib/karafka/pro/processing/strategies/aj/dlq_mom.rb +64 -0
- data/lib/karafka/pro/processing/strategies/aj/dlq_mom_vp.rb +69 -0
- data/lib/karafka/pro/processing/strategies/aj/ftr_lrj_mom.rb +38 -0
- data/lib/karafka/pro/processing/strategies/aj/ftr_lrj_mom_vp.rb +64 -0
- data/lib/karafka/pro/processing/strategies/aj/ftr_mom.rb +38 -0
- data/lib/karafka/pro/processing/strategies/aj/ftr_mom_vp.rb +58 -0
- data/lib/karafka/pro/processing/strategies/aj/lrj_mom.rb +37 -0
- data/lib/karafka/pro/processing/strategies/aj/lrj_mom_vp.rb +79 -0
- data/lib/karafka/pro/processing/strategies/aj/mom.rb +36 -0
- data/lib/karafka/pro/processing/strategies/aj/mom_vp.rb +52 -0
- data/lib/karafka/pro/processing/strategies/base.rb +26 -0
- data/lib/karafka/pro/processing/strategies/default.rb +105 -0
- data/lib/karafka/pro/processing/strategies/dlq/default.rb +131 -0
- data/lib/karafka/pro/processing/strategies/dlq/ftr.rb +61 -0
- data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj.rb +75 -0
- data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj_mom.rb +71 -0
- data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj_mom_vp.rb +43 -0
- data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj_vp.rb +41 -0
- data/lib/karafka/pro/processing/strategies/dlq/ftr_mom.rb +69 -0
- data/lib/karafka/pro/processing/strategies/dlq/ftr_mom_vp.rb +41 -0
- data/lib/karafka/pro/processing/strategies/dlq/ftr_vp.rb +40 -0
- data/lib/karafka/pro/processing/strategies/dlq/lrj.rb +63 -0
- data/lib/karafka/pro/processing/strategies/dlq/lrj_mom.rb +63 -0
- data/lib/karafka/pro/processing/strategies/dlq/lrj_mom_vp.rb +36 -0
- data/lib/karafka/pro/processing/strategies/dlq/lrj_vp.rb +39 -0
- data/lib/karafka/pro/processing/strategies/dlq/mom.rb +68 -0
- data/lib/karafka/pro/processing/strategies/dlq/mom_vp.rb +37 -0
- data/lib/karafka/pro/processing/strategies/dlq/vp.rb +40 -0
- data/lib/karafka/pro/processing/strategies/ftr/default.rb +104 -0
- data/lib/karafka/pro/processing/strategies/ftr/vp.rb +40 -0
- data/lib/karafka/pro/processing/strategies/lrj/default.rb +87 -0
- data/lib/karafka/pro/processing/strategies/lrj/ftr.rb +69 -0
- data/lib/karafka/pro/processing/strategies/lrj/ftr_mom.rb +67 -0
- data/lib/karafka/pro/processing/strategies/lrj/ftr_mom_vp.rb +40 -0
- data/lib/karafka/pro/processing/strategies/lrj/ftr_vp.rb +39 -0
- data/lib/karafka/pro/processing/strategies/lrj/mom.rb +80 -0
- data/lib/karafka/pro/processing/strategies/lrj/mom_vp.rb +38 -0
- data/lib/karafka/pro/processing/strategies/lrj/vp.rb +36 -0
- data/lib/karafka/pro/processing/strategies/mom/default.rb +46 -0
- data/lib/karafka/pro/processing/strategies/mom/ftr.rb +53 -0
- data/lib/karafka/pro/processing/strategies/mom/ftr_vp.rb +37 -0
- data/lib/karafka/pro/processing/strategies/mom/vp.rb +35 -0
- data/lib/karafka/pro/processing/strategies/vp/default.rb +104 -0
- data/lib/karafka/pro/{contracts/base.rb → processing/strategies.rb} +6 -5
- data/lib/karafka/pro/processing/strategy_selector.rb +84 -0
- data/lib/karafka/pro/processing/virtual_offset_manager.rb +147 -0
- data/lib/karafka/pro/routing/features/base.rb +24 -0
- data/lib/karafka/pro/routing/features/dead_letter_queue/contract.rb +50 -0
- data/lib/karafka/pro/routing/features/dead_letter_queue.rb +27 -0
- data/lib/karafka/pro/routing/{builder_extensions.rb → features/delaying/config.rb} +8 -11
- data/lib/karafka/pro/routing/features/delaying/contract.rb +38 -0
- data/lib/karafka/pro/routing/features/delaying/topic.rb +59 -0
- data/lib/karafka/pro/routing/features/delaying.rb +29 -0
- data/lib/karafka/pro/routing/features/expiring/config.rb +27 -0
- data/lib/karafka/pro/routing/features/expiring/contract.rb +38 -0
- data/lib/karafka/pro/routing/features/expiring/topic.rb +59 -0
- data/lib/karafka/pro/routing/features/expiring.rb +27 -0
- data/lib/karafka/pro/routing/features/filtering/config.rb +40 -0
- data/lib/karafka/pro/routing/features/filtering/contract.rb +41 -0
- data/lib/karafka/pro/routing/features/filtering/topic.rb +51 -0
- data/lib/karafka/pro/routing/features/filtering.rb +27 -0
- data/lib/karafka/pro/routing/features/long_running_job/config.rb +28 -0
- data/lib/karafka/pro/routing/features/long_running_job/contract.rb +37 -0
- data/lib/karafka/pro/routing/features/long_running_job/topic.rb +42 -0
- data/lib/karafka/pro/routing/features/long_running_job.rb +28 -0
- data/lib/karafka/pro/routing/features/throttling/config.rb +32 -0
- data/lib/karafka/pro/routing/features/throttling/contract.rb +41 -0
- data/lib/karafka/pro/routing/features/throttling/topic.rb +69 -0
- data/lib/karafka/pro/routing/features/throttling.rb +30 -0
- data/lib/karafka/pro/routing/features/virtual_partitions/config.rb +30 -0
- data/lib/karafka/pro/routing/features/virtual_partitions/contract.rb +52 -0
- data/lib/karafka/pro/routing/features/virtual_partitions/topic.rb +56 -0
- data/lib/karafka/pro/routing/features/virtual_partitions.rb +27 -0
- data/lib/karafka/process.rb +23 -8
- data/lib/karafka/processing/coordinator.rb +102 -23
- data/lib/karafka/processing/coordinators_buffer.rb +5 -1
- data/lib/karafka/processing/executor.rb +51 -21
- data/lib/karafka/processing/executors_buffer.rb +10 -26
- data/lib/karafka/processing/jobs/base.rb +6 -2
- data/lib/karafka/processing/jobs/consume.rb +8 -5
- data/lib/karafka/processing/jobs/idle.rb +24 -0
- data/lib/karafka/processing/jobs_builder.rb +2 -3
- data/lib/karafka/processing/jobs_queue.rb +14 -8
- data/lib/karafka/processing/partitioner.rb +3 -1
- data/lib/karafka/processing/result.rb +14 -1
- data/lib/karafka/processing/strategies/aj_dlq_mom.rb +44 -0
- data/lib/karafka/processing/strategies/aj_mom.rb +21 -0
- data/lib/karafka/processing/strategies/base.rb +52 -0
- data/lib/karafka/processing/strategies/default.rb +142 -0
- data/lib/karafka/processing/strategies/dlq.rb +88 -0
- data/lib/karafka/processing/strategies/dlq_mom.rb +49 -0
- data/lib/karafka/processing/strategies/mom.rb +29 -0
- data/lib/karafka/processing/strategy_selector.rb +47 -0
- data/lib/karafka/processing/worker.rb +8 -3
- data/lib/karafka/railtie.rb +24 -12
- data/lib/karafka/routing/activity_manager.rb +84 -0
- data/lib/karafka/routing/builder.rb +20 -0
- data/lib/karafka/routing/consumer_group.rb +38 -4
- data/lib/karafka/routing/consumer_mapper.rb +0 -10
- data/lib/karafka/routing/features/active_job/builder.rb +33 -0
- data/lib/karafka/routing/features/active_job/config.rb +15 -0
- data/lib/karafka/routing/features/active_job/contract.rb +41 -0
- data/lib/karafka/routing/features/active_job/topic.rb +33 -0
- data/lib/karafka/routing/features/active_job.rb +13 -0
- data/lib/karafka/routing/features/base/expander.rb +53 -0
- data/lib/karafka/routing/features/base.rb +34 -0
- data/lib/karafka/routing/features/dead_letter_queue/config.rb +19 -0
- data/lib/karafka/routing/features/dead_letter_queue/contract.rb +42 -0
- data/lib/karafka/routing/features/dead_letter_queue/topic.rb +41 -0
- data/lib/karafka/routing/features/dead_letter_queue.rb +16 -0
- data/lib/karafka/routing/features/declaratives/config.rb +18 -0
- data/lib/karafka/routing/features/declaratives/contract.rb +30 -0
- data/lib/karafka/routing/features/declaratives/topic.rb +44 -0
- data/lib/karafka/routing/features/declaratives.rb +14 -0
- data/lib/karafka/routing/features/manual_offset_management/config.rb +15 -0
- data/lib/karafka/routing/features/manual_offset_management/contract.rb +24 -0
- data/lib/karafka/routing/features/manual_offset_management/topic.rb +35 -0
- data/lib/karafka/routing/features/manual_offset_management.rb +18 -0
- data/lib/karafka/routing/proxy.rb +18 -20
- data/lib/karafka/routing/router.rb +27 -2
- data/lib/karafka/routing/subscription_group.rb +43 -5
- data/lib/karafka/routing/subscription_groups_builder.rb +6 -1
- data/lib/karafka/routing/topic.rb +17 -5
- data/lib/karafka/routing/topics.rb +8 -0
- data/lib/karafka/runner.rb +1 -0
- data/lib/karafka/serialization/json/deserializer.rb +1 -0
- data/lib/karafka/server.rb +58 -28
- data/lib/karafka/setup/attributes_map.rb +344 -0
- data/lib/karafka/setup/config.rb +48 -19
- data/lib/karafka/status.rb +35 -7
- data/lib/karafka/templates/karafka.rb.erb +14 -6
- data/lib/karafka/time_trackers/base.rb +1 -6
- data/lib/karafka/time_trackers/pause.rb +49 -19
- data/lib/karafka/time_trackers/poll.rb +7 -3
- data/lib/karafka/version.rb +1 -1
- data/lib/karafka.rb +56 -3
- data/renovate.json +6 -0
- data.tar.gz.sig +0 -0
- metadata +189 -61
- metadata.gz.sig +0 -0
- data/bin/wait_for_kafka +0 -20
- data/certs/mensfeld.pem +0 -25
- data/lib/karafka/active_job/routing/extensions.rb +0 -31
- data/lib/karafka/contracts/consumer_group_topic.rb +0 -42
- data/lib/karafka/instrumentation.rb +0 -21
- data/lib/karafka/pro/base_consumer.rb +0 -82
- data/lib/karafka/pro/contracts/consumer_group.rb +0 -34
- data/lib/karafka/pro/contracts/consumer_group_topic.rb +0 -33
- data/lib/karafka/pro/routing/topic_extensions.rb +0 -38
data/lib/karafka/app.rb
CHANGED
|
@@ -14,20 +14,43 @@ module Karafka
|
|
|
14
14
|
.builder
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
# @return [
|
|
17
|
+
# @return [Hash] active subscription groups grouped based on consumer group in a hash
|
|
18
18
|
def subscription_groups
|
|
19
|
+
# We first build all the subscription groups, so they all get the same position, despite
|
|
20
|
+
# later narrowing that. It allows us to maintain same position number for static members
|
|
21
|
+
# even when we want to run subset of consumer groups or subscription groups
|
|
22
|
+
#
|
|
23
|
+
# We then narrow this to active consumer groups from which we select active subscription
|
|
24
|
+
# groups.
|
|
19
25
|
consumer_groups
|
|
20
|
-
.
|
|
21
|
-
.
|
|
26
|
+
.map { |cg| [cg, cg.subscription_groups] }
|
|
27
|
+
.select { |cg, _| cg.active? }
|
|
28
|
+
.select { |_, sgs| sgs.delete_if { |sg| !sg.active? } }
|
|
29
|
+
.delete_if { |_, sgs| sgs.empty? }
|
|
30
|
+
.each { |_, sgs| sgs.each { |sg| sg.topics.delete_if { |top| !top.active? } } }
|
|
31
|
+
.each { |_, sgs| sgs.delete_if { |sg| sg.topics.empty? } }
|
|
32
|
+
.reject { |cg, _| cg.subscription_groups.empty? }
|
|
33
|
+
.to_h
|
|
22
34
|
end
|
|
23
35
|
|
|
24
36
|
# Just a nicer name for the consumer groups
|
|
25
37
|
alias routes consumer_groups
|
|
26
38
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
# Allow for easier status management via `Karafka::App` by aliasing status methods here
|
|
40
|
+
Status::STATES.each do |state, transition|
|
|
41
|
+
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
42
|
+
def #{state}
|
|
43
|
+
App.config.internal.status.#{state}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def #{state}?
|
|
47
|
+
App.config.internal.status.#{state}?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def #{transition}
|
|
51
|
+
App.config.internal.status.#{transition}
|
|
52
|
+
end
|
|
53
|
+
RUBY
|
|
31
54
|
end
|
|
32
55
|
|
|
33
56
|
# Methods that should be delegated to Karafka module
|
|
@@ -4,9 +4,16 @@
|
|
|
4
4
|
module Karafka
|
|
5
5
|
# Base consumer from which all Karafka consumers should inherit
|
|
6
6
|
class BaseConsumer
|
|
7
|
+
# Allow for consumer instance tagging for instrumentation
|
|
8
|
+
include ::Karafka::Core::Taggable
|
|
9
|
+
|
|
10
|
+
extend Forwardable
|
|
11
|
+
|
|
12
|
+
def_delegators :@coordinator, :topic, :partition
|
|
13
|
+
|
|
14
|
+
# @return [String] id of the current consumer
|
|
15
|
+
attr_reader :id
|
|
7
16
|
# @return [Karafka::Routing::Topic] topic to which a given consumer is subscribed
|
|
8
|
-
attr_accessor :topic
|
|
9
|
-
# @return [Karafka::Messages::Messages] current messages batch
|
|
10
17
|
attr_accessor :messages
|
|
11
18
|
# @return [Karafka::Connection::Client] kafka connection client
|
|
12
19
|
attr_accessor :client
|
|
@@ -15,13 +22,49 @@ module Karafka
|
|
|
15
22
|
# @return [Waterdrop::Producer] producer instance
|
|
16
23
|
attr_accessor :producer
|
|
17
24
|
|
|
18
|
-
#
|
|
25
|
+
# Creates new consumer and assigns it an id
|
|
26
|
+
def initialize
|
|
27
|
+
@id = SecureRandom.hex(6)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Can be used to run preparation code prior to the job being enqueued
|
|
19
31
|
#
|
|
20
32
|
# @private
|
|
21
|
-
# @note This should not be used by the end users as it is part of the lifecycle of things
|
|
33
|
+
# @note This should not be used by the end users as it is part of the lifecycle of things and
|
|
34
|
+
# not as a part of the public api. This should not perform any extensive operations as it is
|
|
35
|
+
# blocking and running in the listener thread.
|
|
36
|
+
def on_before_enqueue
|
|
37
|
+
handle_before_enqueue
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
Karafka.monitor.instrument(
|
|
40
|
+
'error.occurred',
|
|
41
|
+
error: e,
|
|
42
|
+
caller: self,
|
|
43
|
+
type: 'consumer.before_enqueue.error'
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Can be used to run preparation code in the worker
|
|
48
|
+
#
|
|
49
|
+
# @private
|
|
50
|
+
# @note This should not be used by the end users as it is part of the lifecycle of things and
|
|
22
51
|
# not as part of the public api. This can act as a hook when creating non-blocking
|
|
23
52
|
# consumers and doing other advanced stuff
|
|
24
|
-
def on_before_consume
|
|
53
|
+
def on_before_consume
|
|
54
|
+
messages.metadata.processed_at = Time.now
|
|
55
|
+
messages.metadata.freeze
|
|
56
|
+
|
|
57
|
+
# We run this after the full metadata setup, so we can use all the messages information
|
|
58
|
+
# if needed
|
|
59
|
+
handle_before_consume
|
|
60
|
+
rescue StandardError => e
|
|
61
|
+
Karafka.monitor.instrument(
|
|
62
|
+
'error.occurred',
|
|
63
|
+
error: e,
|
|
64
|
+
caller: self,
|
|
65
|
+
type: 'consumer.before_consume.error'
|
|
66
|
+
)
|
|
67
|
+
end
|
|
25
68
|
|
|
26
69
|
# Executes the default consumer flow.
|
|
27
70
|
#
|
|
@@ -31,54 +74,50 @@ module Karafka
|
|
|
31
74
|
# that may not yet kick in when error occurs. That way we pause always on the last processed
|
|
32
75
|
# message.
|
|
33
76
|
def on_consume
|
|
34
|
-
|
|
35
|
-
consume
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
coordinator.consumption(self).success!
|
|
77
|
+
handle_consume
|
|
39
78
|
rescue StandardError => e
|
|
40
|
-
coordinator.consumption(self).failure!
|
|
41
|
-
|
|
42
79
|
Karafka.monitor.instrument(
|
|
43
80
|
'error.occurred',
|
|
44
81
|
error: e,
|
|
45
82
|
caller: self,
|
|
83
|
+
seek_offset: coordinator.seek_offset,
|
|
46
84
|
type: 'consumer.consume.error'
|
|
47
85
|
)
|
|
48
|
-
ensure
|
|
49
|
-
# We need to decrease number of jobs that this coordinator coordinates as it has finished
|
|
50
|
-
coordinator.decrement
|
|
51
86
|
end
|
|
52
87
|
|
|
53
88
|
# @private
|
|
54
89
|
# @note This should not be used by the end users as it is part of the lifecycle of things but
|
|
55
90
|
# not as part of the public api.
|
|
56
91
|
def on_after_consume
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
92
|
+
handle_after_consume
|
|
93
|
+
rescue StandardError => e
|
|
94
|
+
Karafka.monitor.instrument(
|
|
95
|
+
'error.occurred',
|
|
96
|
+
error: e,
|
|
97
|
+
caller: self,
|
|
98
|
+
type: 'consumer.after_consume.error'
|
|
99
|
+
)
|
|
100
|
+
end
|
|
64
101
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
102
|
+
# Trigger method for running on idle runs without messages
|
|
103
|
+
#
|
|
104
|
+
# @private
|
|
105
|
+
def on_idle
|
|
106
|
+
handle_idle
|
|
107
|
+
rescue StandardError => e
|
|
108
|
+
Karafka.monitor.instrument(
|
|
109
|
+
'error.occurred',
|
|
110
|
+
error: e,
|
|
111
|
+
caller: self,
|
|
112
|
+
type: 'consumer.idle.error'
|
|
113
|
+
)
|
|
71
114
|
end
|
|
72
115
|
|
|
73
|
-
# Trigger method for running on
|
|
116
|
+
# Trigger method for running on partition revocation.
|
|
74
117
|
#
|
|
75
118
|
# @private
|
|
76
119
|
def on_revoked
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Karafka.monitor.instrument('consumer.revoked', caller: self) do
|
|
80
|
-
revoked
|
|
81
|
-
end
|
|
120
|
+
handle_revoked
|
|
82
121
|
rescue StandardError => e
|
|
83
122
|
Karafka.monitor.instrument(
|
|
84
123
|
'error.occurred',
|
|
@@ -92,9 +131,7 @@ module Karafka
|
|
|
92
131
|
#
|
|
93
132
|
# @private
|
|
94
133
|
def on_shutdown
|
|
95
|
-
|
|
96
|
-
shutdown
|
|
97
|
-
end
|
|
134
|
+
handle_shutdown
|
|
98
135
|
rescue StandardError => e
|
|
99
136
|
Karafka.monitor.instrument(
|
|
100
137
|
'error.occurred',
|
|
@@ -108,7 +145,7 @@ module Karafka
|
|
|
108
145
|
|
|
109
146
|
# Method that will perform business logic and on data received from Kafka (it will consume
|
|
110
147
|
# the data)
|
|
111
|
-
# @note This method needs
|
|
148
|
+
# @note This method needs to be implemented in a subclass. We stub it here as a failover if
|
|
112
149
|
# someone forgets about it or makes on with typo
|
|
113
150
|
def consume
|
|
114
151
|
raise NotImplementedError, 'Implement this in a subclass'
|
|
@@ -122,63 +159,43 @@ module Karafka
|
|
|
122
159
|
# some teardown procedures (closing file handler, etc).
|
|
123
160
|
def shutdown; end
|
|
124
161
|
|
|
125
|
-
# Marks message as consumed in an async way.
|
|
126
|
-
#
|
|
127
|
-
# @param message [Messages::Message] last successfully processed message.
|
|
128
|
-
# @return [Boolean] true if we were able to mark the offset, false otherwise. False indicates
|
|
129
|
-
# that we were not able and that we have lost the partition.
|
|
130
|
-
#
|
|
131
|
-
# @note We keep track of this offset in case we would mark as consumed and got error when
|
|
132
|
-
# processing another message. In case like this we do not pause on the message we've already
|
|
133
|
-
# processed but rather at the next one. This applies to both sync and async versions of this
|
|
134
|
-
# method.
|
|
135
|
-
def mark_as_consumed(message)
|
|
136
|
-
unless client.mark_as_consumed(message)
|
|
137
|
-
coordinator.revoke
|
|
138
|
-
|
|
139
|
-
return false
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
@seek_offset = message.offset + 1
|
|
143
|
-
|
|
144
|
-
true
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
# Marks message as consumed in a sync way.
|
|
148
|
-
#
|
|
149
|
-
# @param message [Messages::Message] last successfully processed message.
|
|
150
|
-
# @return [Boolean] true if we were able to mark the offset, false otherwise. False indicates
|
|
151
|
-
# that we were not able and that we have lost the partition.
|
|
152
|
-
def mark_as_consumed!(message)
|
|
153
|
-
unless client.mark_as_consumed!(message)
|
|
154
|
-
coordinator.revoke
|
|
155
|
-
|
|
156
|
-
return false
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
@seek_offset = message.offset + 1
|
|
160
|
-
|
|
161
|
-
true
|
|
162
|
-
end
|
|
163
|
-
|
|
164
162
|
# Pauses processing on a given offset for the current topic partition
|
|
165
163
|
#
|
|
166
164
|
# After given partition is resumed, it will continue processing from the given offset
|
|
167
165
|
# @param offset [Integer] offset from which we want to restart the processing
|
|
168
166
|
# @param timeout [Integer, nil] how long in milliseconds do we want to pause or nil to use the
|
|
169
167
|
# default exponential pausing strategy defined for retries
|
|
170
|
-
|
|
168
|
+
# @param manual_pause [Boolean] Flag to differentiate between user pause and system/strategy
|
|
169
|
+
# based pause. While they both pause in exactly the same way, the strategy application
|
|
170
|
+
# may need to differentiate between them.
|
|
171
|
+
def pause(offset, timeout = nil, manual_pause = true)
|
|
171
172
|
timeout ? coordinator.pause_tracker.pause(timeout) : coordinator.pause_tracker.pause
|
|
172
173
|
|
|
173
174
|
client.pause(
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
topic.name,
|
|
176
|
+
partition,
|
|
176
177
|
offset
|
|
177
178
|
)
|
|
179
|
+
|
|
180
|
+
# Indicate, that user took a manual action of pausing
|
|
181
|
+
coordinator.manual_pause if manual_pause
|
|
182
|
+
|
|
183
|
+
Karafka.monitor.instrument(
|
|
184
|
+
'consumer.consuming.pause',
|
|
185
|
+
caller: self,
|
|
186
|
+
manual: manual_pause,
|
|
187
|
+
topic: topic.name,
|
|
188
|
+
partition: partition,
|
|
189
|
+
offset: offset,
|
|
190
|
+
timeout: coordinator.pause_tracker.current_timeout,
|
|
191
|
+
attempt: coordinator.pause_tracker.attempt
|
|
192
|
+
)
|
|
178
193
|
end
|
|
179
194
|
|
|
180
195
|
# Resumes processing of the current topic partition
|
|
181
196
|
def resume
|
|
197
|
+
return unless coordinator.pause_tracker.paused?
|
|
198
|
+
|
|
182
199
|
# This is sufficient to expire a partition pause, as with it will be resumed by the listener
|
|
183
200
|
# thread before the next poll.
|
|
184
201
|
coordinator.pause_tracker.expire
|
|
@@ -190,8 +207,8 @@ module Karafka
|
|
|
190
207
|
def seek(offset)
|
|
191
208
|
client.seek(
|
|
192
209
|
Karafka::Messages::Seek.new(
|
|
193
|
-
|
|
194
|
-
|
|
210
|
+
topic.name,
|
|
211
|
+
partition,
|
|
195
212
|
offset
|
|
196
213
|
)
|
|
197
214
|
)
|
|
@@ -203,5 +220,30 @@ module Karafka
|
|
|
203
220
|
def revoked?
|
|
204
221
|
coordinator.revoked?
|
|
205
222
|
end
|
|
223
|
+
|
|
224
|
+
# @return [Boolean] are we retrying processing after an error. This can be used to provide a
|
|
225
|
+
# different flow after there is an error, for example for resources cleanup, small manual
|
|
226
|
+
# backoff or different instrumentation tracking.
|
|
227
|
+
def retrying?
|
|
228
|
+
coordinator.pause_tracker.attempt.positive?
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Pauses the processing from the last offset to retry on given message
|
|
232
|
+
# @private
|
|
233
|
+
def retry_after_pause
|
|
234
|
+
pause(coordinator.seek_offset, nil, false)
|
|
235
|
+
|
|
236
|
+
# Instrumentation needs to run **after** `#pause` invocation because we rely on the states
|
|
237
|
+
# set by `#pause`
|
|
238
|
+
Karafka.monitor.instrument(
|
|
239
|
+
'consumer.consuming.retry',
|
|
240
|
+
caller: self,
|
|
241
|
+
topic: topic.name,
|
|
242
|
+
partition: partition,
|
|
243
|
+
offset: coordinator.seek_offset,
|
|
244
|
+
timeout: coordinator.pause_tracker.current_timeout,
|
|
245
|
+
attempt: coordinator.pause_tracker.attempt
|
|
246
|
+
)
|
|
247
|
+
end
|
|
206
248
|
end
|
|
207
249
|
end
|
data/lib/karafka/cli/base.rb
CHANGED
|
@@ -34,6 +34,26 @@ module Karafka
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
class << self
|
|
37
|
+
# Loads proper environment with what is needed to run the CLI
|
|
38
|
+
def load
|
|
39
|
+
# If there is a boot file, we need to require it as we expect it to contain
|
|
40
|
+
# Karafka app setup, routes, etc
|
|
41
|
+
if File.exist?(::Karafka.boot_file)
|
|
42
|
+
rails_env_rb = File.join(Dir.pwd, 'config/environment.rb')
|
|
43
|
+
|
|
44
|
+
# Load Rails environment file that starts Rails, so we can reference consumers and
|
|
45
|
+
# other things from `karafka.rb` file. This will work only for Rails, for non-rails
|
|
46
|
+
# a manual setup is needed
|
|
47
|
+
require rails_env_rb if Kernel.const_defined?(:Rails) && File.exist?(rails_env_rb)
|
|
48
|
+
|
|
49
|
+
require Karafka.boot_file.to_s
|
|
50
|
+
# However when it is unavailable, we still want to be able to run help command
|
|
51
|
+
# and install command as they don't require configured app itself to run
|
|
52
|
+
elsif %w[-h install].none? { |cmd| cmd == ARGV[0] }
|
|
53
|
+
raise ::Karafka::Errors::MissingBootFileError, ::Karafka.boot_file
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
37
57
|
# Allows to set options for Thor cli
|
|
38
58
|
# @see https://github.com/erikhuda/thor
|
|
39
59
|
# @param option Single option details
|
data/lib/karafka/cli/console.rb
CHANGED
|
@@ -9,22 +9,27 @@ module Karafka
|
|
|
9
9
|
option aliases: 'c'
|
|
10
10
|
|
|
11
11
|
class << self
|
|
12
|
-
# @return [String] Console executing command
|
|
12
|
+
# @return [String] Console executing command for non-Rails setup
|
|
13
13
|
# @example
|
|
14
14
|
# Karafka::Cli::Console.command #=> 'KARAFKA_CONSOLE=true bundle exec irb...'
|
|
15
|
-
def
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
def console
|
|
16
|
+
"IRBRC='#{Karafka.gem_root}/.console_irbrc' bundle exec irb -r #{Karafka.boot_file}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [String] Console executing command for Rails setup
|
|
20
|
+
# @note In case of Rails, it has its own console, hence we can just defer to it
|
|
21
|
+
def rails_console
|
|
22
|
+
'bundle exec rails console'
|
|
21
23
|
end
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
# Start the Karafka console
|
|
25
27
|
def call
|
|
26
28
|
cli.info
|
|
27
|
-
|
|
29
|
+
|
|
30
|
+
command = ::Karafka.rails? ? self.class.rails_console : self.class.console
|
|
31
|
+
|
|
32
|
+
exec "KARAFKA_CONSOLE=true #{command}"
|
|
28
33
|
end
|
|
29
34
|
end
|
|
30
35
|
end
|
data/lib/karafka/cli/info.rb
CHANGED
|
@@ -35,9 +35,10 @@ module Karafka
|
|
|
35
35
|
|
|
36
36
|
[
|
|
37
37
|
"Karafka version: #{Karafka::VERSION}#{postfix}",
|
|
38
|
-
"Ruby version: #{
|
|
38
|
+
"Ruby version: #{RUBY_DESCRIPTION}",
|
|
39
39
|
"Rdkafka version: #{::Rdkafka::VERSION}",
|
|
40
|
-
"
|
|
40
|
+
"Consumer groups count: #{Karafka::App.consumer_groups.size}",
|
|
41
|
+
"Subscription groups count: #{Karafka::App.subscription_groups.values.flatten.size}",
|
|
41
42
|
"Workers count: #{Karafka::App.config.concurrency}",
|
|
42
43
|
"Application client id: #{config.client_id}",
|
|
43
44
|
"Boot file: #{Karafka.boot_file}",
|
data/lib/karafka/cli/server.rb
CHANGED
|
@@ -7,37 +7,84 @@ 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'
|
|
12
|
-
|
|
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
|
|
13
37
|
|
|
14
38
|
# Start the Karafka server
|
|
15
39
|
def call
|
|
16
40
|
# Print our banner and info in the dev mode
|
|
17
41
|
print_marketing_info if Karafka::App.env.development?
|
|
18
42
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
# We assign active topics on a server level, as only server is expected to listen on
|
|
22
|
-
# part of the topics
|
|
23
|
-
Karafka::Server.consumer_groups = cli.options[:consumer_groups]
|
|
43
|
+
register_inclusions(cli)
|
|
44
|
+
register_exclusions(cli)
|
|
24
45
|
|
|
25
46
|
Karafka::Server.run
|
|
26
47
|
end
|
|
27
48
|
|
|
28
49
|
private
|
|
29
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
|
+
|
|
30
77
|
# Prints marketing info
|
|
31
78
|
def print_marketing_info
|
|
32
79
|
Karafka.logger.info Info::BANNER
|
|
33
80
|
|
|
34
81
|
if Karafka.pro?
|
|
35
82
|
Karafka.logger.info(
|
|
36
|
-
green('Thank you for
|
|
83
|
+
green('Thank you for using Karafka Pro!')
|
|
37
84
|
)
|
|
38
85
|
else
|
|
39
86
|
Karafka.logger.info(
|
|
40
|
-
red('
|
|
87
|
+
red('Upgrade to Karafka Pro for more features and support: https://karafka.io')
|
|
41
88
|
)
|
|
42
89
|
end
|
|
43
90
|
end
|
|
@@ -0,0 +1,146 @@
|
|
|
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
|
+
declaratives_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.declaratives.partitions,
|
|
42
|
+
topic.declaratives.replication_factor,
|
|
43
|
+
topic.declaratives.details
|
|
44
|
+
)
|
|
45
|
+
puts "#{green('Created')} topic #{name}."
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Deletes routing based topics
|
|
51
|
+
def delete
|
|
52
|
+
declaratives_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
|
+
declaratives_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 declaratives_routing_topics
|
|
116
|
+
return @declaratives_routing_topics if @declaratives_routing_topics
|
|
117
|
+
|
|
118
|
+
collected_topics = {}
|
|
119
|
+
default_servers = Karafka::App.config.kafka[:'bootstrap.servers']
|
|
120
|
+
|
|
121
|
+
App.consumer_groups.each do |consumer_group|
|
|
122
|
+
consumer_group.topics.each do |topic|
|
|
123
|
+
# Skip topics that were explicitly disabled from management
|
|
124
|
+
next unless topic.declaratives.active?
|
|
125
|
+
# If bootstrap servers are different, consider this a different cluster
|
|
126
|
+
next unless default_servers == topic.kafka[:'bootstrap.servers']
|
|
127
|
+
|
|
128
|
+
collected_topics[topic.name] ||= topic
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
@declaratives_routing_topics = collected_topics.values
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# @return [Array<Hash>] existing topics details
|
|
136
|
+
def existing_topics
|
|
137
|
+
@existing_topics ||= Admin.cluster_info.topics
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# @return [Array<String>] names of already existing topics
|
|
141
|
+
def existing_topics_names
|
|
142
|
+
existing_topics.map { |topic| topic.fetch(:topic_name) }
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|