karafka 2.3.0.alpha2 → 2.3.0.rc1
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/CHANGELOG.md +1 -0
- data/Gemfile.lock +7 -7
- data/config/locales/errors.yml +1 -0
- data/karafka.gemspec +1 -1
- data/lib/karafka/base_consumer.rb +15 -0
- data/lib/karafka/instrumentation/logger_listener.rb +4 -1
- data/lib/karafka/pro/processing/strategies/default.rb +18 -1
- data/lib/karafka/pro/processing/strategies/dlq/default.rb +27 -3
- data/lib/karafka/pro/processing/strategies/dlq/ftr.rb +3 -3
- data/lib/karafka/pro/processing/strategies/dlq/ftr_lrj.rb +2 -3
- data/lib/karafka/pro/processing/strategies/dlq/lrj.rb +2 -3
- data/lib/karafka/routing/features/dead_letter_queue/config.rb +3 -0
- data/lib/karafka/routing/features/dead_letter_queue/contracts/topic.rb +1 -0
- data/lib/karafka/routing/features/dead_letter_queue/topic.rb +6 -2
- data/lib/karafka/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b07678937b0dc9c4154c90ccea2e9bbbc25aa2669461d937e859b77e134ddc48
|
4
|
+
data.tar.gz: a2e3eee8a9351a789dc33a1f78a48899a007da29b81205b4383e75a9fa0cc13c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2331d328849f4ffb65aa5deb921bf8d12d732f06b30acc5b17ef1fb844d5da23166dbcd27a6b53a6d57d76c6a7d508e9c5479e064a73aa6e0c2eaed69597c8a
|
7
|
+
data.tar.gz: da8afa92e4b5fc552319b15322b3b3e883c2ec5c2b46ec887d098d34f7a0fbd7a7408558a89d781699eb521309c8fe69d2df7e6a1f46de19259451fb3050e391
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/CHANGELOG.md
CHANGED
@@ -14,6 +14,7 @@
|
|
14
14
|
- [Enhancement] Provide an `:independent` configuration to DLQ allowing to reset pause count track on each marking as consumed when retrying.
|
15
15
|
- [Enhancement] Remove no longer needed shutdown patches for `librdkafka` improving multi-sg shutdown times for `cooperative-sticky`.
|
16
16
|
- [Enhancement] Allow for parallel closing of connections from independent consumer groups.
|
17
|
+
- [Enhancement] Provide recovery flow for cases where DLQ dispatch would fail.
|
17
18
|
- [Change] Make `Kubernetes::LivenessListener` not start until Karafka app starts running.
|
18
19
|
- [Change] Remove the legacy "inside of topics" way of defining subscription groups names
|
19
20
|
- [Change] Update supported instrumentation to report on `#tick`.
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
karafka (2.3.0.
|
5
|
-
karafka-core (>= 2.3.0.
|
4
|
+
karafka (2.3.0.rc1)
|
5
|
+
karafka-core (>= 2.3.0.rc1, < 2.4.0)
|
6
6
|
waterdrop (>= 2.6.12, < 3.0.0)
|
7
7
|
zeitwerk (~> 2.3)
|
8
8
|
|
@@ -23,7 +23,7 @@ GEM
|
|
23
23
|
mutex_m
|
24
24
|
tzinfo (~> 2.0)
|
25
25
|
base64 (0.2.0)
|
26
|
-
bigdecimal (3.1.
|
26
|
+
bigdecimal (3.1.6)
|
27
27
|
byebug (11.1.3)
|
28
28
|
concurrent-ruby (1.2.3)
|
29
29
|
connection_pool (2.4.1)
|
@@ -39,7 +39,7 @@ GEM
|
|
39
39
|
activesupport (>= 6.1)
|
40
40
|
i18n (1.14.1)
|
41
41
|
concurrent-ruby (~> 1.0)
|
42
|
-
karafka-core (2.3.0.
|
42
|
+
karafka-core (2.3.0.rc1)
|
43
43
|
karafka-rdkafka (>= 0.14.7, < 0.15.0)
|
44
44
|
karafka-rdkafka (0.14.7)
|
45
45
|
ffi (~> 1.15)
|
@@ -52,11 +52,11 @@ GEM
|
|
52
52
|
roda (~> 3.68, >= 3.69)
|
53
53
|
tilt (~> 2.0)
|
54
54
|
mini_portile2 (2.8.5)
|
55
|
-
minitest (5.
|
55
|
+
minitest (5.21.2)
|
56
56
|
mutex_m (0.2.0)
|
57
57
|
rack (3.0.8)
|
58
58
|
rake (13.1.0)
|
59
|
-
roda (3.
|
59
|
+
roda (3.76.0)
|
60
60
|
rack
|
61
61
|
rspec (3.12.0)
|
62
62
|
rspec-core (~> 3.12.0)
|
@@ -100,4 +100,4 @@ DEPENDENCIES
|
|
100
100
|
simplecov
|
101
101
|
|
102
102
|
BUNDLED WITH
|
103
|
-
2.5.
|
103
|
+
2.5.4
|
data/config/locales/errors.yml
CHANGED
@@ -75,6 +75,7 @@ en:
|
|
75
75
|
dead_letter_queue.topic_format: 'needs to be a string with a Kafka accepted format'
|
76
76
|
dead_letter_queue.active_format: needs to be either true or false
|
77
77
|
dead_letter_queue.independent_format: needs to be either true or false
|
78
|
+
dead_letter_queue.transactional_format: needs to be either true or false
|
78
79
|
active_format: needs to be either true or false
|
79
80
|
declaratives.partitions_format: needs to be more or equal to 1
|
80
81
|
declaratives.active_format: needs to be true
|
data/karafka.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
without having to focus on things that are not your business domain.
|
22
22
|
DESC
|
23
23
|
|
24
|
-
spec.add_dependency 'karafka-core', '>= 2.3.0.
|
24
|
+
spec.add_dependency 'karafka-core', '>= 2.3.0.rc1', '< 2.4.0'
|
25
25
|
spec.add_dependency 'waterdrop', '>= 2.6.12', '< 3.0.0'
|
26
26
|
spec.add_dependency 'zeitwerk', '~> 2.3'
|
27
27
|
|
@@ -79,10 +79,25 @@ module Karafka
|
|
79
79
|
end
|
80
80
|
|
81
81
|
# @private
|
82
|
+
#
|
82
83
|
# @note This should not be used by the end users as it is part of the lifecycle of things but
|
83
84
|
# not as part of the public api.
|
85
|
+
#
|
86
|
+
# @note We handle and report errors here because of flows that could fail. For example a DLQ
|
87
|
+
# flow could fail if it was not able to dispatch the DLQ message. Other "non-user" based
|
88
|
+
# flows do not interact with external systems and their errors are expected to bubble up
|
84
89
|
def on_after_consume
|
85
90
|
handle_after_consume
|
91
|
+
rescue StandardError => e
|
92
|
+
Karafka.monitor.instrument(
|
93
|
+
'error.occurred',
|
94
|
+
error: e,
|
95
|
+
caller: self,
|
96
|
+
seek_offset: coordinator.seek_offset,
|
97
|
+
type: 'consumer.after_consume.error'
|
98
|
+
)
|
99
|
+
|
100
|
+
retry_after_pause
|
86
101
|
end
|
87
102
|
|
88
103
|
# Can be used to run code prior to scheduling of idle execution
|
@@ -248,7 +248,10 @@ module Karafka
|
|
248
248
|
error "Consumer on shutdown failed due to an error: #{error}"
|
249
249
|
error details
|
250
250
|
when 'consumer.tick.error'
|
251
|
-
error "Consumer tick failed due to an error: #{error}"
|
251
|
+
error "Consumer on tick failed due to an error: #{error}"
|
252
|
+
error details
|
253
|
+
when 'consumer.after_consume.error'
|
254
|
+
error "Consumer on after_consume failed due to an error: #{error}"
|
252
255
|
error details
|
253
256
|
when 'worker.process.error'
|
254
257
|
fatal "Worker processing failed due to an error: #{error}"
|
@@ -107,8 +107,23 @@ module Karafka
|
|
107
107
|
# allow to mark offsets inside of the transaction. If the transaction is initialized
|
108
108
|
# only from the consumer, the offset will be stored in a regular fashion.
|
109
109
|
#
|
110
|
+
# @param active_producer [WaterDrop::Producer] alternative producer instance we may want
|
111
|
+
# to use. It is useful when we have connection pool or any other selective engine for
|
112
|
+
# managing multiple producers. If not provided, default producer taken from `#producer`
|
113
|
+
# will be used.
|
114
|
+
#
|
110
115
|
# @param block [Proc] code that we want to run in a transaction
|
111
|
-
|
116
|
+
#
|
117
|
+
# @note Please note, that if you provide the producer, it will reassign the producer of
|
118
|
+
# the consumer for the transaction time. This means, that in case you would even
|
119
|
+
# accidentally refer to `Consumer#producer` from other threads, it will contain the
|
120
|
+
# reassigned producer and not the initially used/assigned producer. It is done that
|
121
|
+
# way, so the message producing aliases operate from within transactions and since the
|
122
|
+
# producer in transaction is locked, it will prevent other threads from using it.
|
123
|
+
def transaction(active_producer = producer, &block)
|
124
|
+
default_producer = producer
|
125
|
+
self.producer = active_producer
|
126
|
+
|
112
127
|
transaction_started = false
|
113
128
|
|
114
129
|
# Prevent from nested transactions. It would not make any sense
|
@@ -138,6 +153,8 @@ module Karafka
|
|
138
153
|
marking.pop ? mark_as_consumed(*marking) : mark_as_consumed!(*marking)
|
139
154
|
end
|
140
155
|
ensure
|
156
|
+
self.producer = default_producer
|
157
|
+
|
141
158
|
if transaction_started
|
142
159
|
@_transaction_marked.clear
|
143
160
|
@_in_transaction = false
|
@@ -84,9 +84,7 @@ module Karafka
|
|
84
84
|
else
|
85
85
|
# We reset the pause to indicate we will now consider it as "ok".
|
86
86
|
coordinator.pause_tracker.reset
|
87
|
-
|
88
|
-
dispatch_to_dlq(skippable_message) if dispatch_to_dlq?
|
89
|
-
mark_as_consumed(skippable_message)
|
87
|
+
dispatch_if_needed_and_mark_as_consumed
|
90
88
|
pause(coordinator.seek_offset, nil, false)
|
91
89
|
end
|
92
90
|
end
|
@@ -133,6 +131,25 @@ module Karafka
|
|
133
131
|
)
|
134
132
|
end
|
135
133
|
|
134
|
+
# Dispatches the message to the DLQ (when needed and when applicable based on settings)
|
135
|
+
# and marks this message as consumed for non MOM flows.
|
136
|
+
#
|
137
|
+
# If producer is transactional and config allows, uses transaction to do that
|
138
|
+
def dispatch_if_needed_and_mark_as_consumed
|
139
|
+
skippable_message, = find_skippable_message
|
140
|
+
|
141
|
+
dispatch = lambda do
|
142
|
+
dispatch_to_dlq(skippable_message) if dispatch_to_dlq?
|
143
|
+
mark_as_consumed(skippable_message)
|
144
|
+
end
|
145
|
+
|
146
|
+
if dispatch_in_a_transaction?
|
147
|
+
transaction { dispatch.call }
|
148
|
+
else
|
149
|
+
dispatch.call
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
136
153
|
# @param skippable_message [Array<Karafka::Messages::Message>]
|
137
154
|
# @return [Hash] dispatch DLQ message
|
138
155
|
def build_dlq_message(skippable_message)
|
@@ -168,6 +185,13 @@ module Karafka
|
|
168
185
|
def dispatch_to_dlq?
|
169
186
|
topic.dead_letter_queue.topic
|
170
187
|
end
|
188
|
+
|
189
|
+
# @return [Boolean] should we use a transaction to move the data to the DLQ.
|
190
|
+
# We can do it only when producer is transactional and configuration for DLQ
|
191
|
+
# transactional dispatches is not set to false.
|
192
|
+
def dispatch_in_a_transaction?
|
193
|
+
producer.transactional? && topic.dead_letter_queue.transactional?
|
194
|
+
end
|
171
195
|
end
|
172
196
|
end
|
173
197
|
end
|
@@ -46,9 +46,9 @@ module Karafka
|
|
46
46
|
retry_after_pause
|
47
47
|
else
|
48
48
|
coordinator.pause_tracker.reset
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
|
50
|
+
dispatch_if_needed_and_mark_as_consumed
|
51
|
+
|
52
52
|
pause(coordinator.seek_offset, nil, false)
|
53
53
|
end
|
54
54
|
end
|
@@ -60,9 +60,8 @@ module Karafka
|
|
60
60
|
|
61
61
|
return resume if revoked?
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
mark_as_consumed(skippable_message)
|
63
|
+
dispatch_if_needed_and_mark_as_consumed
|
64
|
+
|
66
65
|
pause(coordinator.seek_offset, nil, false)
|
67
66
|
end
|
68
67
|
end
|
@@ -49,9 +49,8 @@ module Karafka
|
|
49
49
|
|
50
50
|
return resume if revoked?
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
mark_as_consumed(skippable_message)
|
52
|
+
dispatch_if_needed_and_mark_as_consumed
|
53
|
+
|
55
54
|
pause(coordinator.seek_offset, nil, false)
|
56
55
|
end
|
57
56
|
end
|
@@ -13,10 +13,13 @@ module Karafka
|
|
13
13
|
:topic,
|
14
14
|
# Should retries be handled collectively on a batch or independently per message
|
15
15
|
:independent,
|
16
|
+
# Move to DLQ and mark as consumed in transactional mode (if applicable)
|
17
|
+
:transactional,
|
16
18
|
keyword_init: true
|
17
19
|
) do
|
18
20
|
alias_method :active?, :active
|
19
21
|
alias_method :independent?, :independent
|
22
|
+
alias_method :transactional?, :transactional
|
20
23
|
end
|
21
24
|
end
|
22
25
|
end
|
@@ -20,6 +20,7 @@ module Karafka
|
|
20
20
|
required(:active) { |val| [true, false].include?(val) }
|
21
21
|
required(:independent) { |val| [true, false].include?(val) }
|
22
22
|
required(:max_retries) { |val| val.is_a?(Integer) && val >= 0 }
|
23
|
+
required(:transactional) { |val| [true, false].include?(val) }
|
23
24
|
end
|
24
25
|
|
25
26
|
# Validate topic name only if dlq is active
|
@@ -16,17 +16,21 @@ module Karafka
|
|
16
16
|
# if we do not want to move it anywhere and just skip
|
17
17
|
# @param independent [Boolean] needs to be true in order for each marking as consumed
|
18
18
|
# in a retry flow to reset the errors counter
|
19
|
+
# @param transactional [Boolean] if applicable, should transaction be used to move
|
20
|
+
# given message to the dead-letter topic and mark it as consumed.
|
19
21
|
# @return [Config] defined config
|
20
22
|
def dead_letter_queue(
|
21
23
|
max_retries: DEFAULT_MAX_RETRIES,
|
22
24
|
topic: nil,
|
23
|
-
independent: false
|
25
|
+
independent: false,
|
26
|
+
transactional: true
|
24
27
|
)
|
25
28
|
@dead_letter_queue ||= Config.new(
|
26
29
|
active: !topic.nil?,
|
27
30
|
max_retries: max_retries,
|
28
31
|
topic: topic,
|
29
|
-
independent: independent
|
32
|
+
independent: independent,
|
33
|
+
transactional: transactional
|
30
34
|
)
|
31
35
|
end
|
32
36
|
|
data/lib/karafka/version.rb
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: karafka
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.0.
|
4
|
+
version: 2.3.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maciej Mensfeld
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
AnG1dJU+yL2BK7vaVytLTstJME5mepSZ46qqIJXMuWob/YPDmVaBF39TDSG9e34s
|
36
36
|
msG3BiCqgOgHAnL23+CN3Rt8MsuRfEtoTKpJVcCfoEoNHOkc
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2024-01-
|
38
|
+
date: 2024-01-21 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: karafka-core
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
requirements:
|
44
44
|
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 2.3.0.
|
46
|
+
version: 2.3.0.rc1
|
47
47
|
- - "<"
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: 2.4.0
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
requirements:
|
54
54
|
- - ">="
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: 2.3.0.
|
56
|
+
version: 2.3.0.rc1
|
57
57
|
- - "<"
|
58
58
|
- !ruby/object:Gem::Version
|
59
59
|
version: 2.4.0
|
metadata.gz.sig
CHANGED
Binary file
|