karafka 2.6.0.beta1 → 2.6.0.rc2
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
- data/CHANGELOG.md +66 -27
- data/certs/expired.txt +2 -0
- data/config/locales/errors.yml +5 -0
- data/config/locales/pro_errors.yml +5 -5
- data/karafka.gemspec +1 -1
- data/lib/active_job/queue_adapters/karafka_adapter.rb +1 -1
- data/lib/karafka/active_job/current_attributes/loading.rb +1 -1
- data/lib/karafka/active_job/current_attributes.rb +4 -2
- data/lib/karafka/active_job/dispatcher.rb +1 -2
- data/lib/karafka/admin/consumer_groups.rb +8 -2
- data/lib/karafka/admin/replication.rb +6 -3
- data/lib/karafka/admin/topics.rb +32 -12
- data/lib/karafka/admin.rb +155 -59
- data/lib/karafka/app.rb +1 -1
- data/lib/karafka/base_consumer.rb +33 -5
- data/lib/karafka/cli/console.rb +0 -1
- data/lib/karafka/cli/help.rb +0 -1
- data/lib/karafka/cli/info.rb +0 -1
- data/lib/karafka/cli/install.rb +0 -1
- data/lib/karafka/cli/server.rb +0 -1
- data/lib/karafka/cli/swarm.rb +0 -1
- data/lib/karafka/cli.rb +2 -2
- data/lib/karafka/connection/client.rb +44 -7
- data/lib/karafka/connection/listener.rb +3 -3
- data/lib/karafka/connection/manager.rb +0 -1
- data/lib/karafka/connection/pauses_manager.rb +20 -3
- data/lib/karafka/connection/proxy.rb +45 -0
- data/lib/karafka/connection/status.rb +0 -1
- data/lib/karafka/instrumentation/assignments_tracker.rb +34 -0
- data/lib/karafka/instrumentation/callbacks/consumer_groups/decorator.rb +19 -0
- data/lib/karafka/instrumentation/callbacks/consumer_groups/error.rb +0 -1
- data/lib/karafka/instrumentation/callbacks/consumer_groups/statistics.rb +3 -2
- data/lib/karafka/instrumentation/critical_errors_listener.rb +85 -0
- data/lib/karafka/instrumentation/logger_listener.rb +2 -0
- data/lib/karafka/instrumentation/monitor.rb +2 -3
- data/lib/karafka/instrumentation/vendors/appsignal/errors_listener.rb +0 -1
- data/lib/karafka/instrumentation/vendors/appsignal/metrics_listener.rb +0 -1
- data/lib/karafka/instrumentation/vendors/datadog/logger_listener.rb +4 -3
- data/lib/karafka/instrumentation/vendors/datadog/metrics_listener.rb +0 -2
- data/lib/karafka/instrumentation/vendors/kubernetes/liveness_listener.rb +181 -18
- data/lib/karafka/pro/admin/recovery/errors.rb +0 -1
- data/lib/karafka/pro/admin/recovery.rb +6 -4
- data/lib/karafka/pro/base_consumer.rb +5 -5
- data/lib/karafka/pro/cleaner/messages/metadata.rb +0 -1
- data/lib/karafka/pro/cli/parallel_segments/base.rb +1 -2
- data/lib/karafka/pro/connection/manager.rb +7 -4
- data/lib/karafka/pro/encryption/messages/middleware.rb +5 -0
- data/lib/karafka/pro/encryption/messages/parser.rb +4 -0
- data/lib/karafka/pro/instrumentation/callbacks/consumer_groups/decorator.rb +63 -0
- data/lib/karafka/pro/instrumentation/consumer_groups/lag_compensation/compensator.rb +120 -0
- data/lib/karafka/pro/instrumentation/consumer_groups/lag_compensation/fetcher.rb +88 -0
- data/lib/karafka/pro/instrumentation/consumer_groups/lag_compensation/refresher.rb +185 -0
- data/lib/karafka/pro/instrumentation/consumer_groups/lag_compensation/registry.rb +102 -0
- data/lib/karafka/pro/instrumentation/performance_tracker.rb +40 -6
- data/lib/karafka/pro/iterator/tpl_builder.rb +27 -7
- data/lib/karafka/pro/iterator.rb +22 -7
- data/lib/karafka/pro/loader.rb +12 -0
- data/lib/karafka/pro/processing/consumer_groups/adaptive_iterator/consumer.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/adaptive_iterator/tracker.rb +2 -4
- data/lib/karafka/pro/processing/consumer_groups/collapser.rb +6 -9
- data/lib/karafka/pro/processing/consumer_groups/coordinator.rb +1 -4
- data/lib/karafka/pro/processing/consumer_groups/coordinators/errors_tracker.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/coordinators/filters_applier.rb +21 -10
- data/lib/karafka/pro/processing/consumer_groups/coordinators/virtual_offset_manager.rb +4 -4
- data/lib/karafka/pro/processing/consumer_groups/expansions_selector.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/filters/actions.rb +84 -0
- data/lib/karafka/pro/processing/consumer_groups/filters/base.rb +5 -6
- data/lib/karafka/pro/processing/consumer_groups/filters/delayer.rb +2 -5
- data/lib/karafka/pro/processing/consumer_groups/filters/expirer.rb +1 -4
- data/lib/karafka/pro/processing/consumer_groups/filters/inline_insights_delayer.rb +1 -4
- data/lib/karafka/pro/processing/consumer_groups/filters/throttler.rb +2 -5
- data/lib/karafka/pro/processing/consumer_groups/filters/virtual_limiter.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/jobs/consume_non_blocking.rb +2 -3
- data/lib/karafka/pro/processing/consumer_groups/jobs/eofed_non_blocking.rb +0 -2
- data/lib/karafka/pro/processing/consumer_groups/jobs/periodic.rb +2 -3
- data/lib/karafka/pro/processing/consumer_groups/jobs/periodic_non_blocking.rb +0 -2
- data/lib/karafka/pro/processing/consumer_groups/jobs/revoked_non_blocking.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/jobs_builder.rb +5 -4
- data/lib/karafka/pro/processing/consumer_groups/offset_metadata/consumer.rb +3 -7
- data/lib/karafka/pro/processing/consumer_groups/offset_metadata/fetcher.rb +8 -10
- data/lib/karafka/pro/processing/consumer_groups/offset_metadata/listener.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/parallel_segments/filters/base.rb +3 -5
- data/lib/karafka/pro/processing/consumer_groups/parallel_segments/filters/default.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/parallel_segments/filters/mom.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/partitioner.rb +2 -5
- data/lib/karafka/pro/processing/consumer_groups/periodic_job/consumer.rb +2 -5
- data/lib/karafka/pro/processing/consumer_groups/piping/consumer.rb +2 -5
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_ftr_lrj_mom.rb +10 -9
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_ftr_lrj_mom_vp.rb +11 -10
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_ftr_mom.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_ftr_mom_vp.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_lrj_mom.rb +8 -7
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_lrj_mom_vp.rb +9 -8
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_mom.rb +5 -8
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/dlq_mom_vp.rb +3 -6
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/ftr_lrj_mom.rb +4 -7
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/ftr_lrj_mom_vp.rb +6 -9
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/ftr_mom.rb +3 -7
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/ftr_mom_vp.rb +4 -8
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/lrj_mom.rb +3 -6
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/lrj_mom_vp.rb +4 -7
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/mom.rb +2 -5
- data/lib/karafka/pro/processing/consumer_groups/strategies/aj/mom_vp.rb +3 -6
- data/lib/karafka/pro/processing/consumer_groups/strategies/base.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/default.rb +56 -33
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/default.rb +27 -14
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_lrj.rb +4 -7
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_lrj_mom.rb +5 -8
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_lrj_mom_vp.rb +5 -8
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_lrj_vp.rb +3 -7
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_mom.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_mom_vp.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/ftr_vp.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/lrj.rb +2 -5
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/lrj_mom.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/lrj_mom_vp.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/lrj_vp.rb +3 -6
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/mom.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/mom_vp.rb +3 -6
- data/lib/karafka/pro/processing/consumer_groups/strategies/dlq/vp.rb +65 -8
- data/lib/karafka/pro/processing/consumer_groups/strategies/ftr/default.rb +0 -4
- data/lib/karafka/pro/processing/consumer_groups/strategies/ftr/vp.rb +2 -5
- data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/default.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/ftr.rb +3 -6
- data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/ftr_mom.rb +4 -7
- data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/ftr_mom_vp.rb +4 -8
- data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/ftr_vp.rb +3 -6
- data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/mom.rb +2 -5
- data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/mom_vp.rb +3 -7
- data/lib/karafka/pro/processing/consumer_groups/strategies/lrj/vp.rb +2 -5
- data/lib/karafka/pro/processing/consumer_groups/strategies/mom/default.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/mom/ftr.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/mom/ftr_vp.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/mom/vp.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/strategies/vp/default.rb +11 -6
- data/lib/karafka/pro/processing/consumer_groups/strategy_selector.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/subscription_groups_coordinator.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/virtual_partitions/distributors/balanced.rb +0 -3
- data/lib/karafka/pro/processing/consumer_groups/virtual_partitions/distributors/base.rb +2 -4
- data/lib/karafka/pro/processing/consumer_groups/virtual_partitions/distributors/consistent.rb +0 -3
- data/lib/karafka/pro/processing/jobs_queue.rb +4 -1
- data/lib/karafka/pro/processing/schedulers/base.rb +4 -2
- data/lib/karafka/pro/processing/schedulers/default.rb +2 -2
- data/lib/karafka/pro/recurring_tasks/consumer.rb +9 -2
- data/lib/karafka/pro/recurring_tasks/contracts/config.rb +0 -1
- data/lib/karafka/pro/recurring_tasks/executor.rb +25 -13
- data/lib/karafka/pro/routing/features/consumer_groups/direct_assignments/subscription_group.rb +0 -2
- data/lib/karafka/pro/routing/features/consumer_groups/long_running_job.rb +0 -2
- data/lib/karafka/pro/routing/features/consumer_groups/multiplexing/proxy.rb +2 -2
- data/lib/karafka/pro/routing/features/consumer_groups/non_blocking_job.rb +0 -2
- data/lib/karafka/pro/routing/features/consumer_groups/offset_metadata/topic.rb +0 -6
- data/lib/karafka/pro/routing/features/consumer_groups/parallel_segments/consumer_group.rb +5 -4
- data/lib/karafka/pro/routing/features/consumer_groups/patterns/config.rb +0 -6
- data/lib/karafka/pro/routing/features/consumer_groups/patterns/consumer_group.rb +2 -1
- data/lib/karafka/pro/routing/features/consumer_groups/patterns/contracts/pattern.rb +0 -1
- data/lib/karafka/pro/routing/features/consumer_groups/patterns/detector.rb +2 -1
- data/lib/karafka/pro/routing/features/consumer_groups/patterns/pattern.rb +2 -1
- data/lib/karafka/pro/routing/features/consumer_groups/patterns/topics.rb +8 -8
- data/lib/karafka/pro/routing/features/consumer_groups/periodic_job/topic.rb +5 -5
- data/lib/karafka/pro/routing/features/consumer_groups/recurring_tasks/builder.rb +34 -15
- data/lib/karafka/pro/routing/features/consumer_groups/scheduled_messages/builder.rb +52 -28
- data/lib/karafka/pro/routing/features/consumer_groups/scheduled_messages/topic.rb +2 -1
- data/lib/karafka/pro/routing/features/consumer_groups/virtual_partitions/topic.rb +6 -5
- data/lib/karafka/pro/routing/features/pausing/config.rb +7 -11
- data/lib/karafka/pro/routing/features/pausing/contracts/topic.rb +6 -8
- data/lib/karafka/pro/routing/features/pausing/topic.rb +18 -63
- data/lib/karafka/pro/scheduled_messages/consumer.rb +7 -1
- data/lib/karafka/pro/scheduled_messages/schema_validator.rb +6 -1
- data/lib/karafka/pro/swarm/liveness_listener.rb +118 -13
- data/lib/karafka/pro.rb +0 -6
- data/lib/karafka/processing/consumer_groups/coordinator.rb +4 -5
- data/lib/karafka/processing/consumer_groups/coordinators_buffer.rb +6 -2
- data/lib/karafka/processing/consumer_groups/executor.rb +4 -4
- data/lib/karafka/processing/consumer_groups/executors_buffer.rb +2 -4
- data/lib/karafka/processing/consumer_groups/expansions_selector.rb +0 -2
- data/lib/karafka/processing/consumer_groups/inline_insights/consumer.rb +0 -2
- data/lib/karafka/processing/consumer_groups/inline_insights/listener.rb +0 -2
- data/lib/karafka/processing/consumer_groups/inline_insights/tracker.rb +14 -16
- data/lib/karafka/processing/consumer_groups/jobs/consume.rb +2 -5
- data/lib/karafka/processing/consumer_groups/jobs/eofed.rb +2 -3
- data/lib/karafka/processing/consumer_groups/jobs/idle.rb +2 -2
- data/lib/karafka/processing/consumer_groups/jobs/revoked.rb +2 -4
- data/lib/karafka/processing/consumer_groups/jobs/shutdown.rb +2 -2
- data/lib/karafka/processing/consumer_groups/partitioner.rb +3 -6
- data/lib/karafka/processing/consumer_groups/strategies/aj_dlq_mom.rb +5 -2
- data/lib/karafka/processing/consumer_groups/strategies/aj_mom.rb +2 -4
- data/lib/karafka/processing/consumer_groups/strategies/base.rb +3 -5
- data/lib/karafka/processing/consumer_groups/strategies/default.rb +43 -13
- data/lib/karafka/processing/consumer_groups/strategies/dlq.rb +5 -2
- data/lib/karafka/processing/consumer_groups/strategies/dlq_mom.rb +5 -2
- data/lib/karafka/processing/consumer_groups/strategies/mom.rb +2 -3
- data/lib/karafka/processing/consumer_groups/strategy_selector.rb +0 -2
- data/lib/karafka/processing/coordinator.rb +0 -2
- data/lib/karafka/processing/coordinators_buffer.rb +0 -2
- data/lib/karafka/processing/partitioner.rb +0 -2
- data/lib/karafka/processing/strategy_selector.rb +0 -2
- data/lib/karafka/processing/worker.rb +14 -6
- data/lib/karafka/processing/workers_pool.rb +21 -4
- data/lib/karafka/railtie.rb +0 -1
- data/lib/karafka/routing/contracts/routing.rb +2 -2
- data/lib/karafka/routing/features/consumer_groups/active_job/topic.rb +6 -5
- data/lib/karafka/routing/features/consumer_groups/manual_offset_management/topic.rb +2 -2
- data/lib/karafka/routing/features/deserializers/topic.rb +0 -1
- data/lib/karafka/routing/features/pausing/config.rb +27 -0
- data/lib/karafka/routing/features/pausing.rb +13 -0
- data/lib/karafka/routing/subscription_group.rb +1 -1
- data/lib/karafka/routing/topic.rb +20 -7
- data/lib/karafka/routing/topics.rb +21 -1
- data/lib/karafka/server.rb +9 -0
- data/lib/karafka/setup/config.rb +52 -55
- data/lib/karafka/setup/config_proxy.rb +2 -1
- data/lib/karafka/setup/contracts/config.rb +14 -0
- data/lib/karafka/swarm/node.rb +2 -2
- data/lib/karafka/version.rb +1 -2
- data/lib/karafka.rb +2 -2
- metadata +14 -4
|
@@ -47,28 +47,50 @@ module Karafka
|
|
|
47
47
|
# - 1 - polling ttl exceeded
|
|
48
48
|
# - 2 - consuming ttl exceeded
|
|
49
49
|
# - 3 - memory limit exceeded
|
|
50
|
+
# - 4 - stability ttl exceeded (stuck in non-steady librdkafka join state)
|
|
50
51
|
#
|
|
51
52
|
# @note This listener should not break anything if subscribed in the supervisor prior to
|
|
52
53
|
# forking as it relies on server events for operations.
|
|
53
54
|
class LivenessListener < Karafka::Swarm::LivenessListener
|
|
55
|
+
# Default time in ms after which we consider consumption hanging (5 minutes)
|
|
56
|
+
DEFAULT_CONSUMING_TTL = 5 * 60 * 1_000
|
|
57
|
+
# Default max time in ms between polls before the node is considered dead (5 minutes)
|
|
58
|
+
DEFAULT_POLLING_TTL = 5 * 60 * 1_000
|
|
59
|
+
# Multiplier applied to max.poll.interval.ms when deriving the default stability_ttl.
|
|
60
|
+
STABILITY_TTL_MAX_POLL_MULTIPLIER = 2
|
|
61
|
+
|
|
62
|
+
private_constant(
|
|
63
|
+
:DEFAULT_CONSUMING_TTL,
|
|
64
|
+
:DEFAULT_POLLING_TTL,
|
|
65
|
+
:STABILITY_TTL_MAX_POLL_MULTIPLIER
|
|
66
|
+
)
|
|
67
|
+
|
|
54
68
|
# @param memory_limit [Integer] max memory in MB for this process to be considered healthy
|
|
55
|
-
# @param consuming_ttl [Integer]
|
|
56
|
-
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
69
|
+
# @param consuming_ttl [Integer] see Kubernetes::LivenessListener for full documentation.
|
|
70
|
+
# @param polling_ttl [Integer] see Kubernetes::LivenessListener for full documentation.
|
|
71
|
+
# @param stability_ttl [Integer, nil] see Kubernetes::LivenessListener for full
|
|
72
|
+
# documentation, including the derivation rules (max `max.poll.interval.ms` across
|
|
73
|
+
# all active subscription groups, times 2, resolved lazily on first health
|
|
74
|
+
# evaluation). Same semantics apply here; the node is reported unhealthy with
|
|
75
|
+
# status code 4 instead of returning HTTP 500.
|
|
61
76
|
def initialize(
|
|
62
77
|
memory_limit: Float::INFINITY,
|
|
63
|
-
consuming_ttl:
|
|
64
|
-
polling_ttl:
|
|
78
|
+
consuming_ttl: DEFAULT_CONSUMING_TTL,
|
|
79
|
+
polling_ttl: DEFAULT_POLLING_TTL,
|
|
80
|
+
stability_ttl: nil
|
|
65
81
|
)
|
|
66
82
|
@polling_ttl = polling_ttl
|
|
67
83
|
@consuming_ttl = consuming_ttl
|
|
84
|
+
# When nil, resolved lazily via #stability_ttl on first health evaluation because
|
|
85
|
+
# the default derives from the routing subscription groups, which may not be drawn
|
|
86
|
+
# yet when the listener is constructed in karafka.rb
|
|
87
|
+
@stability_ttl = stability_ttl
|
|
68
88
|
# We cast it just in case someone would provide '10MB' or something similar
|
|
69
89
|
@memory_limit = memory_limit.is_a?(String) ? memory_limit.to_i : memory_limit
|
|
70
90
|
@pollings = {}
|
|
71
91
|
@consumptions = {}
|
|
92
|
+
@join_states = {}
|
|
93
|
+
@instabilities = {}
|
|
72
94
|
|
|
73
95
|
super()
|
|
74
96
|
end
|
|
@@ -117,6 +139,27 @@ module Karafka
|
|
|
117
139
|
RUBY
|
|
118
140
|
end
|
|
119
141
|
|
|
142
|
+
# @see Karafka::Instrumentation::Vendors::Kubernetes::LivenessListener#on_statistics_emitted
|
|
143
|
+
# @param event [Karafka::Core::Monitoring::Event]
|
|
144
|
+
def on_statistics_emitted(event)
|
|
145
|
+
cgrp = event[:statistics]&.dig("cgrp")
|
|
146
|
+
return unless cgrp
|
|
147
|
+
|
|
148
|
+
sg_id = event[:subscription_group_id]
|
|
149
|
+
join_state = cgrp["join_state"]
|
|
150
|
+
return unless join_state
|
|
151
|
+
|
|
152
|
+
synchronize do
|
|
153
|
+
if join_state == "steady" || join_state == "init" || join_state == "wait-metadata"
|
|
154
|
+
@instabilities.delete(sg_id)
|
|
155
|
+
@join_states.delete(sg_id)
|
|
156
|
+
elsif @join_states[sg_id] != join_state
|
|
157
|
+
@join_states[sg_id] = join_state
|
|
158
|
+
@instabilities[sg_id] = monotonic_now
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
120
163
|
# @param _event [Karafka::Core::Monitoring::Event]
|
|
121
164
|
def on_error_occurred(_event)
|
|
122
165
|
clear_consumption_tick
|
|
@@ -143,6 +186,13 @@ module Karafka
|
|
|
143
186
|
clear_polling_tick
|
|
144
187
|
end
|
|
145
188
|
|
|
189
|
+
# @see Karafka::Instrumentation::Vendors::Kubernetes::LivenessListener
|
|
190
|
+
# #on_connection_listener_after_fetch_loop
|
|
191
|
+
# @param event [Karafka::Core::Monitoring::Event]
|
|
192
|
+
def on_connection_listener_after_fetch_loop(event)
|
|
193
|
+
clear_instability_tracking(event[:subscription_group])
|
|
194
|
+
end
|
|
195
|
+
|
|
146
196
|
private
|
|
147
197
|
|
|
148
198
|
# Reports the current status to the supervisor periodically
|
|
@@ -158,10 +208,21 @@ module Karafka
|
|
|
158
208
|
end
|
|
159
209
|
end
|
|
160
210
|
|
|
161
|
-
# @
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
|
|
211
|
+
# @see Karafka::Instrumentation::Vendors::Kubernetes::LivenessListener
|
|
212
|
+
# #clear_instability_tracking
|
|
213
|
+
# @param subscription_group [Karafka::Routing::SubscriptionGroup, nil]
|
|
214
|
+
def clear_instability_tracking(subscription_group)
|
|
215
|
+
return unless subscription_group
|
|
216
|
+
|
|
217
|
+
sg_id = subscription_group.id
|
|
218
|
+
|
|
219
|
+
synchronize do
|
|
220
|
+
@instabilities.delete(sg_id)
|
|
221
|
+
@join_states.delete(sg_id)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# @see Karafka::Instrumentation::Vendors::Kubernetes::LivenessListener#fiber_id
|
|
165
226
|
def fiber_id
|
|
166
227
|
Fiber.current.object_id
|
|
167
228
|
end
|
|
@@ -195,17 +256,61 @@ module Karafka
|
|
|
195
256
|
end
|
|
196
257
|
|
|
197
258
|
# Did we exceed any of the ttls
|
|
198
|
-
# @return [
|
|
259
|
+
# @return [Integer] 0 if healthy, positive error code otherwise:
|
|
260
|
+
# 1 - polling TTL exceeded
|
|
261
|
+
# 2 - consuming TTL exceeded
|
|
262
|
+
# 3 - memory limit exceeded
|
|
263
|
+
# 4 - stability TTL exceeded (stuck in non-steady join state)
|
|
264
|
+
# @note Reads `@pollings`, `@consumptions` and `@instabilities` without acquiring the
|
|
265
|
+
# mutex. This is intentional and consistent across all three: `status` is called from
|
|
266
|
+
# inside `periodically`, which already holds `@mutex` for scheduling, so re-entering
|
|
267
|
+
# `synchronize` here would deadlock. Concurrent writes from `mark_*` / `clear_*` /
|
|
268
|
+
# `on_statistics_emitted` are safe to observe partially on MRI (GVL atomises Hash ops).
|
|
269
|
+
# This is the asymmetry vs `Kubernetes::LivenessListener`, which can lock its reads
|
|
270
|
+
# because it has no equivalent periodic-scheduling lock. Do not "fix" this without
|
|
271
|
+
# resolving the periodic-scheduling lock first - JRuby is not a supported runtime.
|
|
199
272
|
def status
|
|
200
273
|
time = monotonic_now
|
|
201
274
|
|
|
202
275
|
return 1 if @pollings.values.any? { |tick| (time - tick) > @polling_ttl }
|
|
203
276
|
return 2 if @consumptions.values.any? { |tick| (time - tick) > @consuming_ttl }
|
|
204
277
|
return 3 if rss_mb > @memory_limit
|
|
278
|
+
return 4 if @instabilities.values.any? { |start| (time - start) > stability_ttl }
|
|
205
279
|
|
|
206
280
|
0
|
|
207
281
|
end
|
|
208
282
|
|
|
283
|
+
# @return [Integer] effective stability ttl in ms. Resolved lazily (instead of in
|
|
284
|
+
# `#initialize`) because the default derives from the routing subscription groups,
|
|
285
|
+
# which may not be drawn yet when the listener is constructed in karafka.rb. By the
|
|
286
|
+
# time status is evaluated, routing is final.
|
|
287
|
+
def stability_ttl
|
|
288
|
+
@stability_ttl ||= default_stability_ttl
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# @return [Integer] default stability_ttl derived from the configured
|
|
292
|
+
# max.poll.interval.ms, multiplied by 2 for headroom above the slowest legitimate
|
|
293
|
+
# rebalance phase. Uses the maximum value across all active subscription groups
|
|
294
|
+
# (their kafka configs already have librdkafka defaults injected), so per
|
|
295
|
+
# subscription group overrides set via the routing DSL are respected. Falls back to
|
|
296
|
+
# the root kafka config when no subscription groups are available.
|
|
297
|
+
def default_stability_ttl
|
|
298
|
+
max_poll_interval = Karafka::App
|
|
299
|
+
.subscription_groups
|
|
300
|
+
.values
|
|
301
|
+
.flatten
|
|
302
|
+
.map { |sg| sg.kafka.fetch(:"max.poll.interval.ms") }
|
|
303
|
+
.max
|
|
304
|
+
|
|
305
|
+
max_poll_interval ||= begin
|
|
306
|
+
kafka_config = Karafka::App.config.kafka.dup
|
|
307
|
+
Karafka::Setup::DefaultsInjector.consumer(kafka_config)
|
|
308
|
+
kafka_config.fetch(:"max.poll.interval.ms")
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
max_poll_interval * STABILITY_TTL_MAX_POLL_MULTIPLIER
|
|
312
|
+
end
|
|
313
|
+
|
|
209
314
|
# @return [Integer] RSS in MB for the current process
|
|
210
315
|
def rss_mb
|
|
211
316
|
RUBY_PLATFORM.include?("linux") ? rss_mb_linux : rss_mb_macos
|
data/lib/karafka/pro.rb
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# This Karafka component is a Pro component.
|
|
4
|
-
# All of the commercial components are present in the lib/karafka/pro directory of this repository
|
|
5
|
-
# and their usage requires commercial license agreement.
|
|
6
|
-
#
|
|
7
|
-
# Karafka has also commercial-friendly license, commercial support and commercial components.
|
|
8
|
-
#
|
|
9
3
|
module Karafka
|
|
10
4
|
# Namespace for pro components, licensed under the commercial license agreement.
|
|
11
5
|
module Pro
|
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
# Basic coordinator that allows us to provide coordination objects into consumers.
|
|
9
7
|
#
|
|
10
8
|
# This is a wrapping layer to simplify management of work to be handled around consumption.
|
|
11
9
|
#
|
|
12
10
|
# @note This coordinator needs to be thread safe. Some operations are performed only in the
|
|
13
|
-
# listener thread, but we go with thread-safe by default for all not to worry about
|
|
14
|
-
# future mistakes.
|
|
11
|
+
# listener thread, but we go with thread-safe by default for all not to worry about
|
|
12
|
+
# potential future mistakes.
|
|
15
13
|
class Coordinator
|
|
16
14
|
extend Forwardable
|
|
17
15
|
include Core::Helpers::Time
|
|
@@ -29,7 +27,8 @@ module Karafka
|
|
|
29
27
|
|
|
30
28
|
# @param topic [Karafka::Routing::Topic]
|
|
31
29
|
# @param partition [Integer]
|
|
32
|
-
# @param pause_tracker [Karafka::TimeTrackers::Pause] pause tracker for given topic
|
|
30
|
+
# @param pause_tracker [Karafka::TimeTrackers::Pause] pause tracker for given topic
|
|
31
|
+
# partition
|
|
33
32
|
def initialize(topic, partition, pause_tracker)
|
|
34
33
|
@topic = topic
|
|
35
34
|
@partition = partition
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
# Coordinators builder used to build coordinators per topic partition
|
|
9
7
|
#
|
|
@@ -50,6 +48,12 @@ module Karafka
|
|
|
50
48
|
def revoke(topic_name, partition)
|
|
51
49
|
return unless @coordinators[topic_name].key?(partition)
|
|
52
50
|
|
|
51
|
+
# Reset the partition's pause tracker attempt count. The tracker lives in the pauses
|
|
52
|
+
# manager keyed by topic-partition and would otherwise be reused as-is if we reclaim this
|
|
53
|
+
# partition, carrying a stale retry attempt count across the rebalance (which, with DLQ,
|
|
54
|
+
# would send the next failure straight to the dead letter queue, skipping the retries)
|
|
55
|
+
@pauses_manager.revoke(@topics.find(topic_name), partition)
|
|
56
|
+
|
|
53
57
|
# The fact that we delete here does not change the fact that the executor still holds the
|
|
54
58
|
# reference to this coordinator. We delete it here, as we will no longer process any
|
|
55
59
|
# new stuff with it and we may need a new coordinator if we regain this partition, but the
|
|
@@ -7,8 +7,8 @@ module Karafka
|
|
|
7
7
|
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
8
8
|
module ConsumerGroups
|
|
9
9
|
# Executors:
|
|
10
|
-
# - run consumers code (for `#call`) or run given preparation / teardown operations when
|
|
11
|
-
# from separate threads.
|
|
10
|
+
# - run consumers code (for `#call`) or run given preparation / teardown operations when
|
|
11
|
+
# needed from separate threads.
|
|
12
12
|
# - they re-create consumer instances in case of partitions that were revoked and assigned
|
|
13
13
|
# back.
|
|
14
14
|
#
|
|
@@ -54,8 +54,8 @@ module Karafka
|
|
|
54
54
|
@coordinator = coordinator
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
# Allows us to prepare the consumer in the listener thread prior to the job being send to
|
|
58
|
-
#
|
|
57
|
+
# Allows us to prepare the consumer in the listener thread prior to the job being send to be
|
|
58
|
+
# scheduled. It also allows to run some code that is time sensitive and cannot wait in the
|
|
59
59
|
# queue as it could cause starvation.
|
|
60
60
|
#
|
|
61
61
|
# @param messages [Array<Karafka::Messages::Message>]
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
# Buffer for executors of a given subscription group. It wraps around the concept of building
|
|
9
7
|
# and caching them, so we can re-use them instead of creating new each time.
|
|
@@ -63,8 +61,8 @@ module Karafka
|
|
|
63
61
|
#
|
|
64
62
|
# @param topic [String] topic name
|
|
65
63
|
# @param partition [Integer] partition number
|
|
66
|
-
# @return [Array<Executor, Pro::Processing::ConsumerGroups::Executor>] executors in use for
|
|
67
|
-
# topic + partition
|
|
64
|
+
# @return [Array<Executor, Pro::Processing::ConsumerGroups::Executor>] executors in use for
|
|
65
|
+
# this topic + partition
|
|
68
66
|
def find_all(topic, partition)
|
|
69
67
|
@buffer[topic][partition].values
|
|
70
68
|
end
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
# Selector of appropriate topic setup based features enhancements.
|
|
9
7
|
#
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
# Namespace of the Inline Insights feature "non routing" related components
|
|
9
7
|
#
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
module InlineInsights
|
|
9
7
|
# Listener that adds statistics to our inline tracker
|
|
@@ -2,31 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
module InlineInsights
|
|
9
7
|
# Object used to track statistics coming from librdkafka in a way that can be accessible by
|
|
10
8
|
# the consumers
|
|
11
9
|
#
|
|
12
|
-
# We use a single tracker because we do not need state management here as our consumer
|
|
13
|
-
# clients identified by statistics name value are unique. On top of that, having a
|
|
14
|
-
# process one that is a singleton allows us to use tracker easily also from other places
|
|
15
|
-
# filtering API etc.
|
|
10
|
+
# We use a single tracker because we do not need state management here as our consumer
|
|
11
|
+
# groups clients identified by statistics name value are unique. On top of that, having a
|
|
12
|
+
# per process one that is a singleton allows us to use tracker easily also from other places
|
|
13
|
+
# like filtering API etc.
|
|
16
14
|
#
|
|
17
15
|
# @note We include cache of 5 minutes for revoked partitions to compensate for cases where
|
|
18
|
-
# when using LRJ a lost partition data would not be present anymore, however we would
|
|
19
|
-
# be in the processing phase. Since those metrics are published with each `poll`,
|
|
20
|
-
# processing is not a subject of this issue. For LRJ we keep the reference. The
|
|
21
|
-
# where this could be switched midway is when LRJ is running for an extended
|
|
22
|
-
# after the involuntary revocation. Having a time based cache instead of
|
|
23
|
-
# simplifies the design as we do not have to deal with state tracking, especially
|
|
24
|
-
# we would have to track also operations running in a revoked state.
|
|
16
|
+
# when using LRJ a lost partition data would not be present anymore, however we would
|
|
17
|
+
# still be in the processing phase. Since those metrics are published with each `poll`,
|
|
18
|
+
# regular processing is not a subject of this issue. For LRJ we keep the reference. The
|
|
19
|
+
# only case where this could be switched midway is when LRJ is running for an extended
|
|
20
|
+
# period of time after the involuntary revocation. Having a time based cache instead of
|
|
21
|
+
# tracking simplifies the design as we do not have to deal with state tracking, especially
|
|
22
|
+
# since we would have to track also operations running in a revoked state.
|
|
25
23
|
#
|
|
26
24
|
# @note This tracker keeps in memory data about all topics and partitions that it encounters
|
|
27
|
-
# because in case of routing patterns, we may start getting statistics prior to
|
|
28
|
-
# given topic via dynamic routing expansions. In such case we would not have
|
|
29
|
-
# where they were actually available for us to use.
|
|
25
|
+
# because in case of routing patterns, we may start getting statistics prior to
|
|
26
|
+
# registering given topic via dynamic routing expansions. In such case we would not have
|
|
27
|
+
# insights where they were actually available for us to use.
|
|
30
28
|
#
|
|
31
29
|
# @note Memory usage is negligible as long as we can evict expired data. Single metrics set
|
|
32
30
|
# for a single partition contains around 4KB of data. This means, that in case of an
|
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
|
-
# Consumer-group-specific job types
|
|
9
6
|
module Jobs
|
|
10
7
|
# The main job type. It runs the executor that triggers given topic partition messages
|
|
11
8
|
# processing in an underlying consumer instance.
|
|
@@ -15,8 +12,8 @@ module Karafka
|
|
|
15
12
|
|
|
16
13
|
self.action = :consume
|
|
17
14
|
|
|
18
|
-
# @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is suppose
|
|
19
|
-
# job
|
|
15
|
+
# @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is suppose
|
|
16
|
+
# to run a given job
|
|
20
17
|
# @param messages [Karafka::Messages::Messages] karafka messages batch
|
|
21
18
|
# @return [Consume]
|
|
22
19
|
def initialize(executor, messages)
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
# Consumer-group-specific job types
|
|
9
7
|
module Jobs
|
|
@@ -11,7 +9,8 @@ module Karafka
|
|
|
11
9
|
class Eofed < ::Karafka::Processing::Jobs::Base
|
|
12
10
|
self.action = :eofed
|
|
13
11
|
|
|
14
|
-
# @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is
|
|
12
|
+
# @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is
|
|
13
|
+
# supposed to run the job
|
|
15
14
|
# @return [Eofed]
|
|
16
15
|
def initialize(executor)
|
|
17
16
|
@executor = executor
|
|
@@ -9,8 +9,8 @@ module Karafka
|
|
|
9
9
|
class Idle < ::Karafka::Processing::Jobs::Base
|
|
10
10
|
self.action = :idle
|
|
11
11
|
|
|
12
|
-
# @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is
|
|
13
|
-
# job on an active consumer
|
|
12
|
+
# @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is
|
|
13
|
+
# supposed to run a given job on an active consumer
|
|
14
14
|
# @return [Idle]
|
|
15
15
|
def initialize(executor)
|
|
16
16
|
@executor = executor
|
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
|
-
# Consumer-group-specific job types
|
|
9
6
|
module Jobs
|
|
10
7
|
# Job that runs the revoked operation when we lose a partition on a consumer that lost it.
|
|
11
8
|
class Revoked < ::Karafka::Processing::Jobs::Base
|
|
12
9
|
self.action = :revoked
|
|
13
10
|
|
|
14
|
-
# @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is
|
|
11
|
+
# @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is
|
|
12
|
+
# supposed to run the job
|
|
15
13
|
# @return [Revoked]
|
|
16
14
|
def initialize(executor)
|
|
17
15
|
@executor = executor
|
|
@@ -8,8 +8,8 @@ module Karafka
|
|
|
8
8
|
class Shutdown < ::Karafka::Processing::Jobs::Base
|
|
9
9
|
self.action = :shutdown
|
|
10
10
|
|
|
11
|
-
# @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is
|
|
12
|
-
# job on an active consumer
|
|
11
|
+
# @param executor [Karafka::Processing::ConsumerGroups::Executor] executor that is
|
|
12
|
+
# supposed to run a given job on an active consumer
|
|
13
13
|
# @return [Shutdown]
|
|
14
14
|
def initialize(executor)
|
|
15
15
|
@executor = executor
|
|
@@ -2,11 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
|
-
# Basic partitioner for work division
|
|
9
|
-
# It does not divide any work.
|
|
6
|
+
# Basic partitioner for work division. It does not divide any work.
|
|
10
7
|
class Partitioner
|
|
11
8
|
# @param subscription_group [Karafka::Routing::SubscriptionGroup] subscription group
|
|
12
9
|
def initialize(subscription_group)
|
|
@@ -15,8 +12,8 @@ module Karafka
|
|
|
15
12
|
|
|
16
13
|
# @param _topic [String] topic name
|
|
17
14
|
# @param messages [Array<Karafka::Messages::Message>] karafka messages
|
|
18
|
-
# @param _coordinator [Karafka::Processing::ConsumerGroups::Coordinator] processing
|
|
19
|
-
# be used with those messages
|
|
15
|
+
# @param _coordinator [Karafka::Processing::ConsumerGroups::Coordinator] processing
|
|
16
|
+
# coordinator that will be used with those messages
|
|
20
17
|
# @yieldparam [Integer] group id
|
|
21
18
|
# @yieldparam [Array<Karafka::Messages::Message>] karafka messages
|
|
22
19
|
def call(_topic, messages, _coordinator)
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
module Strategies
|
|
9
7
|
# ActiveJob strategy to cooperate with the DLQ.
|
|
@@ -28,6 +26,11 @@ module Karafka
|
|
|
28
26
|
if coordinator.success?
|
|
29
27
|
# Do NOT commit offsets, they are comitted after each job in the AJ consumer.
|
|
30
28
|
coordinator.pause_tracker.reset
|
|
29
|
+
# Process-critical errors are never dispatched to the DLQ regardless of the retries
|
|
30
|
+
# state: the retry pause protects the partition during the critical shutdown and
|
|
31
|
+
# the failed batch is redelivered after the restart
|
|
32
|
+
elsif critical_error?(coordinator.consumption(self).cause)
|
|
33
|
+
retry_after_pause
|
|
31
34
|
elsif coordinator.pause_tracker.attempt <= topic.dead_letter_queue.max_retries
|
|
32
35
|
retry_after_pause
|
|
33
36
|
else
|
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
module Strategies
|
|
9
|
-
# ActiveJob enabled
|
|
10
|
-
# Manual offset management enabled
|
|
7
|
+
# - ActiveJob enabled
|
|
8
|
+
# - Manual offset management enabled
|
|
11
9
|
#
|
|
12
10
|
# This is the default AJ strategy since AJ cannot be used without MOM
|
|
13
11
|
module AjMom
|
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
|
-
# Our processing patterns differ depending on various features configurations
|
|
9
|
-
#
|
|
10
|
-
#
|
|
6
|
+
# Our processing patterns differ depending on various features configurations. In this
|
|
7
|
+
# namespace we collect strategies for particular feature combinations to simplify the design.
|
|
8
|
+
# Based on features combinations we can then select handling strategy for a given case.
|
|
11
9
|
#
|
|
12
10
|
# @note The lack of common code here is intentional. It would get complex if there would be
|
|
13
11
|
# any type of composition, so each strategy is expected to be self-sufficient
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
module Karafka
|
|
4
4
|
module Processing
|
|
5
|
-
# Consumer-group-specific processing components (driven by rebalance callbacks and partition
|
|
6
|
-
# ticks). Parallel `ShareGroups` will live next to this namespace once KIP-932 lands.
|
|
7
5
|
module ConsumerGroups
|
|
8
6
|
module Strategies
|
|
9
|
-
# No features enabled
|
|
10
|
-
# No manual offset management
|
|
11
|
-
# No long running jobs
|
|
7
|
+
# No features enabled:
|
|
8
|
+
# - No manual offset management
|
|
9
|
+
# - No long running jobs
|
|
10
|
+
#
|
|
12
11
|
# Nothing. Just standard, automatic flow
|
|
13
12
|
module Default
|
|
14
13
|
include Base
|
|
@@ -59,9 +58,18 @@ module Karafka
|
|
|
59
58
|
# In case like this we ignore marking
|
|
60
59
|
return true if seek_offset.nil?
|
|
61
60
|
# Ignore double markings of the same offset
|
|
61
|
+
# Only this exact re-mark is skipped - marking genuinely older offsets is intentionally
|
|
62
|
+
# allowed and rewinds the seek offset for reprocessing (see #2432)
|
|
62
63
|
return true if (seek_offset - 1) == message.offset
|
|
63
64
|
return false if revoked?
|
|
64
|
-
|
|
65
|
+
unless client.mark_as_consumed(message)
|
|
66
|
+
# Evaluate ownership for its coordinator-revoking side effect - all marking
|
|
67
|
+
# failure causes are ownership related. The failure itself always reports false:
|
|
68
|
+
# the offset was not stored, regardless of the current ownership state
|
|
69
|
+
revoked?
|
|
70
|
+
|
|
71
|
+
return false
|
|
72
|
+
end
|
|
65
73
|
|
|
66
74
|
self.seek_offset = message.offset + 1
|
|
67
75
|
|
|
@@ -78,10 +86,19 @@ module Karafka
|
|
|
78
86
|
# In case like this we ignore marking
|
|
79
87
|
return true if seek_offset.nil?
|
|
80
88
|
# Ignore double markings of the same offset
|
|
89
|
+
# Only this exact re-mark is skipped - marking genuinely older offsets is intentionally
|
|
90
|
+
# allowed and rewinds the seek offset for reprocessing (see #2432)
|
|
81
91
|
return true if (seek_offset - 1) == message.offset
|
|
82
92
|
return false if revoked?
|
|
83
93
|
|
|
84
|
-
|
|
94
|
+
unless client.mark_as_consumed!(message)
|
|
95
|
+
# Evaluate ownership for its coordinator-revoking side effect - all marking
|
|
96
|
+
# failure causes are ownership related. The failure itself always reports false:
|
|
97
|
+
# the offset was not committed, regardless of the current ownership state
|
|
98
|
+
revoked?
|
|
99
|
+
|
|
100
|
+
return false
|
|
101
|
+
end
|
|
85
102
|
|
|
86
103
|
self.seek_offset = message.offset + 1
|
|
87
104
|
|
|
@@ -91,17 +108,27 @@ module Karafka
|
|
|
91
108
|
# Triggers an async offset commit
|
|
92
109
|
#
|
|
93
110
|
# @param async [Boolean] should we use async (default) or sync commit
|
|
94
|
-
# @return [Boolean] true if we still
|
|
111
|
+
# @return [Boolean] true if the commit went through and we still owned the partition
|
|
112
|
+
# at that time, false otherwise. False means the offsets were not committed - the
|
|
113
|
+
# caller can retry (the offsets stay stored client-side) or treat the partition as
|
|
114
|
+
# fenced.
|
|
95
115
|
# @note Due to its async nature, this may not fully represent the offset state in some
|
|
96
116
|
# edge cases (like for example going beyond max.poll.interval)
|
|
117
|
+
# @note A commit with no offsets pending is a client-side no-op reported as success
|
|
118
|
+
# without broker validation - the marking result is the fence for that case.
|
|
97
119
|
def commit_offsets(async: true)
|
|
98
120
|
# Do not commit if we already lost the assignment
|
|
99
121
|
return false if revoked?
|
|
100
122
|
return true if client.commit_offsets(async: async)
|
|
101
123
|
|
|
102
|
-
#
|
|
103
|
-
#
|
|
124
|
+
# Evaluate ownership once more for its coordinator-revoking side effect: all
|
|
125
|
+
# commit failure causes the client reports as false are ownership related. The
|
|
126
|
+
# failed commit itself always reports false - its value must not depend on the
|
|
127
|
+
# revocation state, which may not yet be locally visible (or may indicate a
|
|
128
|
+
# retained partition under a cooperative rebalance generation bump)
|
|
104
129
|
revoked?
|
|
130
|
+
|
|
131
|
+
false
|
|
105
132
|
end
|
|
106
133
|
|
|
107
134
|
# Triggers a synchronous offsets commit to Kafka
|
|
@@ -138,7 +165,10 @@ module Karafka
|
|
|
138
165
|
|
|
139
166
|
# Mark job as successful
|
|
140
167
|
coordinator.success!(self)
|
|
141
|
-
|
|
168
|
+
# Failure recording must be class-agnostic: an unrecorded non-StandardError would
|
|
169
|
+
# leave the consumption result in its default (successful) state and the after-consume
|
|
170
|
+
# flow would mark the failed batch as consumed instead of engaging the retry
|
|
171
|
+
rescue Exception => e
|
|
142
172
|
coordinator.failure!(self, e)
|
|
143
173
|
|
|
144
174
|
# Re-raise so reported in the consumer
|
|
@@ -187,8 +217,8 @@ module Karafka
|
|
|
187
217
|
end
|
|
188
218
|
|
|
189
219
|
# We need to always un-pause the processing in case we have lost a given partition.
|
|
190
|
-
# Otherwise the underlying librdkafka would not know we may want to continue processing
|
|
191
|
-
# the pause could in theory last forever
|
|
220
|
+
# Otherwise the underlying librdkafka would not know we may want to continue processing
|
|
221
|
+
# and the pause could in theory last forever
|
|
192
222
|
def handle_revoked
|
|
193
223
|
resume
|
|
194
224
|
|