karafka-rdkafka 0.13.2 → 0.13.9
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/workflows/ci.yml +9 -4
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +54 -26
- data/{LICENSE → MIT-LICENSE} +2 -1
- data/README.md +19 -20
- data/certs/cert_chain.pem +21 -21
- data/docker-compose.yml +16 -15
- data/ext/README.md +1 -1
- data/ext/Rakefile +1 -1
- data/karafka-rdkafka.gemspec +2 -2
- data/lib/rdkafka/abstract_handle.rb +41 -27
- data/lib/rdkafka/admin/create_partitions_handle.rb +6 -3
- data/lib/rdkafka/admin/create_topic_handle.rb +6 -3
- data/lib/rdkafka/admin/delete_topic_handle.rb +6 -3
- data/lib/rdkafka/admin.rb +6 -7
- data/lib/rdkafka/bindings.rb +24 -6
- data/lib/rdkafka/config.rb +53 -19
- data/lib/rdkafka/consumer/headers.rb +2 -4
- data/lib/rdkafka/consumer.rb +119 -93
- data/lib/rdkafka/error.rb +60 -1
- data/lib/rdkafka/helpers/time.rb +14 -0
- data/lib/rdkafka/metadata.rb +4 -4
- data/lib/rdkafka/native_kafka.rb +6 -1
- data/lib/rdkafka/producer/delivery_handle.rb +16 -1
- data/lib/rdkafka/producer/delivery_report.rb +3 -2
- data/lib/rdkafka/producer.rb +89 -17
- data/lib/rdkafka/version.rb +3 -3
- data/lib/rdkafka.rb +10 -1
- data/renovate.json +6 -0
- data/spec/rdkafka/abstract_handle_spec.rb +0 -2
- data/spec/rdkafka/admin/create_topic_handle_spec.rb +4 -4
- data/spec/rdkafka/admin/create_topic_report_spec.rb +0 -2
- data/spec/rdkafka/admin/delete_topic_handle_spec.rb +3 -3
- data/spec/rdkafka/admin/delete_topic_report_spec.rb +0 -2
- data/spec/rdkafka/admin_spec.rb +1 -2
- data/spec/rdkafka/bindings_spec.rb +0 -1
- data/spec/rdkafka/callbacks_spec.rb +0 -2
- data/spec/rdkafka/config_spec.rb +8 -2
- data/spec/rdkafka/consumer/headers_spec.rb +0 -2
- data/spec/rdkafka/consumer/message_spec.rb +0 -2
- data/spec/rdkafka/consumer/partition_spec.rb +0 -2
- data/spec/rdkafka/consumer/topic_partition_list_spec.rb +0 -2
- data/spec/rdkafka/consumer_spec.rb +122 -38
- data/spec/rdkafka/error_spec.rb +0 -2
- data/spec/rdkafka/metadata_spec.rb +2 -3
- data/spec/rdkafka/native_kafka_spec.rb +2 -3
- data/spec/rdkafka/producer/delivery_handle_spec.rb +15 -2
- data/spec/rdkafka/producer/delivery_report_spec.rb +0 -2
- data/spec/rdkafka/producer_spec.rb +293 -1
- data/spec/spec_helper.rb +7 -1
- data.tar.gz.sig +0 -0
- metadata +31 -28
- metadata.gz.sig +0 -0
- data/certs/karafka-pro.pem +0 -11
data/lib/rdkafka/consumer.rb
CHANGED
@@ -12,6 +12,7 @@ module Rdkafka
|
|
12
12
|
# `each_slice` to consume batches of messages.
|
13
13
|
class Consumer
|
14
14
|
include Enumerable
|
15
|
+
include Helpers::Time
|
15
16
|
|
16
17
|
# @private
|
17
18
|
def initialize(native_kafka)
|
@@ -29,6 +30,13 @@ module Rdkafka
|
|
29
30
|
->(_) { close }
|
30
31
|
end
|
31
32
|
|
33
|
+
# @return [String] consumer name
|
34
|
+
def name
|
35
|
+
@name ||= @native_kafka.with_inner do |inner|
|
36
|
+
::Rdkafka::Bindings.rd_kafka_name(inner)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
32
40
|
# Close this consumer
|
33
41
|
# @return [nil]
|
34
42
|
def close
|
@@ -47,13 +55,11 @@ module Rdkafka
|
|
47
55
|
@native_kafka.closed?
|
48
56
|
end
|
49
57
|
|
50
|
-
#
|
58
|
+
# Subscribes to one or more topics letting Kafka handle partition assignments.
|
51
59
|
#
|
52
60
|
# @param topics [Array<String>] One or more topic names
|
53
|
-
#
|
54
|
-
# @raise [RdkafkaError] When subscribing fails
|
55
|
-
#
|
56
61
|
# @return [nil]
|
62
|
+
# @raise [RdkafkaError] When subscribing fails
|
57
63
|
def subscribe(*topics)
|
58
64
|
closed_consumer_check(__method__)
|
59
65
|
|
@@ -68,36 +74,33 @@ module Rdkafka
|
|
68
74
|
response = @native_kafka.with_inner do |inner|
|
69
75
|
Rdkafka::Bindings.rd_kafka_subscribe(inner, tpl)
|
70
76
|
end
|
71
|
-
|
72
|
-
|
73
|
-
end
|
77
|
+
|
78
|
+
Rdkafka::RdkafkaError.validate!(response, "Error subscribing to '#{topics.join(', ')}'")
|
74
79
|
ensure
|
75
80
|
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl) unless tpl.nil?
|
76
81
|
end
|
77
82
|
|
78
83
|
# Unsubscribe from all subscribed topics.
|
79
84
|
#
|
80
|
-
# @raise [RdkafkaError] When unsubscribing fails
|
81
|
-
#
|
82
85
|
# @return [nil]
|
86
|
+
# @raise [RdkafkaError] When unsubscribing fails
|
83
87
|
def unsubscribe
|
84
88
|
closed_consumer_check(__method__)
|
85
89
|
|
86
90
|
response = @native_kafka.with_inner do |inner|
|
87
91
|
Rdkafka::Bindings.rd_kafka_unsubscribe(inner)
|
88
92
|
end
|
89
|
-
|
90
|
-
|
91
|
-
|
93
|
+
|
94
|
+
Rdkafka::RdkafkaError.validate!(response)
|
95
|
+
|
96
|
+
nil
|
92
97
|
end
|
93
98
|
|
94
99
|
# Pause producing or consumption for the provided list of partitions
|
95
100
|
#
|
96
101
|
# @param list [TopicPartitionList] The topic with partitions to pause
|
97
|
-
#
|
98
|
-
# @raise [RdkafkaTopicPartitionListError] When pausing subscription fails.
|
99
|
-
#
|
100
102
|
# @return [nil]
|
103
|
+
# @raise [RdkafkaTopicPartitionListError] When pausing subscription fails.
|
101
104
|
def pause(list)
|
102
105
|
closed_consumer_check(__method__)
|
103
106
|
|
@@ -121,13 +124,11 @@ module Rdkafka
|
|
121
124
|
end
|
122
125
|
end
|
123
126
|
|
124
|
-
#
|
127
|
+
# Resumes producing consumption for the provided list of partitions
|
125
128
|
#
|
126
129
|
# @param list [TopicPartitionList] The topic with partitions to pause
|
127
|
-
#
|
128
|
-
# @raise [RdkafkaError] When resume subscription fails.
|
129
|
-
#
|
130
130
|
# @return [nil]
|
131
|
+
# @raise [RdkafkaError] When resume subscription fails.
|
131
132
|
def resume(list)
|
132
133
|
closed_consumer_check(__method__)
|
133
134
|
|
@@ -141,19 +142,19 @@ module Rdkafka
|
|
141
142
|
response = @native_kafka.with_inner do |inner|
|
142
143
|
Rdkafka::Bindings.rd_kafka_resume_partitions(inner, tpl)
|
143
144
|
end
|
144
|
-
|
145
|
-
|
146
|
-
|
145
|
+
|
146
|
+
Rdkafka::RdkafkaError.validate!(response, "Error resume '#{list.to_h}'")
|
147
|
+
|
148
|
+
nil
|
147
149
|
ensure
|
148
150
|
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl)
|
149
151
|
end
|
150
152
|
end
|
151
153
|
|
152
|
-
#
|
153
|
-
#
|
154
|
-
# @raise [RdkafkaError] When getting the subscription fails.
|
154
|
+
# Returns the current subscription to topics and partitions
|
155
155
|
#
|
156
156
|
# @return [TopicPartitionList]
|
157
|
+
# @raise [RdkafkaError] When getting the subscription fails.
|
157
158
|
def subscription
|
158
159
|
closed_consumer_check(__method__)
|
159
160
|
|
@@ -162,9 +163,7 @@ module Rdkafka
|
|
162
163
|
Rdkafka::Bindings.rd_kafka_subscription(inner, ptr)
|
163
164
|
end
|
164
165
|
|
165
|
-
|
166
|
-
raise Rdkafka::RdkafkaError.new(response)
|
167
|
-
end
|
166
|
+
Rdkafka::RdkafkaError.validate!(response)
|
168
167
|
|
169
168
|
native = ptr.read_pointer
|
170
169
|
|
@@ -178,7 +177,6 @@ module Rdkafka
|
|
178
177
|
# Atomic assignment of partitions to consume
|
179
178
|
#
|
180
179
|
# @param list [TopicPartitionList] The topic with partitions to assign
|
181
|
-
#
|
182
180
|
# @raise [RdkafkaError] When assigning fails
|
183
181
|
def assign(list)
|
184
182
|
closed_consumer_check(__method__)
|
@@ -193,9 +191,8 @@ module Rdkafka
|
|
193
191
|
response = @native_kafka.with_inner do |inner|
|
194
192
|
Rdkafka::Bindings.rd_kafka_assign(inner, tpl)
|
195
193
|
end
|
196
|
-
|
197
|
-
|
198
|
-
end
|
194
|
+
|
195
|
+
Rdkafka::RdkafkaError.validate!(response, "Error assigning '#{list.to_h}'")
|
199
196
|
ensure
|
200
197
|
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl)
|
201
198
|
end
|
@@ -203,9 +200,8 @@ module Rdkafka
|
|
203
200
|
|
204
201
|
# Returns the current partition assignment.
|
205
202
|
#
|
206
|
-
# @raise [RdkafkaError] When getting the assignment fails.
|
207
|
-
#
|
208
203
|
# @return [TopicPartitionList]
|
204
|
+
# @raise [RdkafkaError] When getting the assignment fails.
|
209
205
|
def assignment
|
210
206
|
closed_consumer_check(__method__)
|
211
207
|
|
@@ -213,9 +209,8 @@ module Rdkafka
|
|
213
209
|
response = @native_kafka.with_inner do |inner|
|
214
210
|
Rdkafka::Bindings.rd_kafka_assignment(inner, ptr)
|
215
211
|
end
|
216
|
-
|
217
|
-
|
218
|
-
end
|
212
|
+
|
213
|
+
Rdkafka::RdkafkaError.validate!(response)
|
219
214
|
|
220
215
|
tpl = ptr.read_pointer
|
221
216
|
|
@@ -240,14 +235,14 @@ module Rdkafka
|
|
240
235
|
end
|
241
236
|
|
242
237
|
# Return the current committed offset per partition for this consumer group.
|
243
|
-
# The offset field of each requested partition will either be set to stored offset or to -1001
|
238
|
+
# The offset field of each requested partition will either be set to stored offset or to -1001
|
239
|
+
# in case there was no stored offset for that partition.
|
244
240
|
#
|
245
|
-
# @param list [TopicPartitionList, nil] The topic with partitions to get the offsets for or nil
|
241
|
+
# @param list [TopicPartitionList, nil] The topic with partitions to get the offsets for or nil
|
242
|
+
# to use the current subscription.
|
246
243
|
# @param timeout_ms [Integer] The timeout for fetching this information.
|
247
|
-
#
|
248
|
-
# @raise [RdkafkaError] When getting the committed positions fails.
|
249
|
-
#
|
250
244
|
# @return [TopicPartitionList]
|
245
|
+
# @raise [RdkafkaError] When getting the committed positions fails.
|
251
246
|
def committed(list=nil, timeout_ms=1200)
|
252
247
|
closed_consumer_check(__method__)
|
253
248
|
|
@@ -263,24 +258,48 @@ module Rdkafka
|
|
263
258
|
response = @native_kafka.with_inner do |inner|
|
264
259
|
Rdkafka::Bindings.rd_kafka_committed(inner, tpl, timeout_ms)
|
265
260
|
end
|
266
|
-
|
267
|
-
|
268
|
-
|
261
|
+
|
262
|
+
Rdkafka::RdkafkaError.validate!(response)
|
263
|
+
|
269
264
|
TopicPartitionList.from_native_tpl(tpl)
|
270
265
|
ensure
|
271
266
|
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl)
|
272
267
|
end
|
273
268
|
end
|
274
269
|
|
270
|
+
# Return the current positions (offsets) for topics and partitions.
|
271
|
+
# The offset field of each requested partition will be set to the offset of the last consumed message + 1, or nil in case there was no previous message.
|
272
|
+
#
|
273
|
+
# @param list [TopicPartitionList, nil] The topic with partitions to get the offsets for or nil to use the current subscription.
|
274
|
+
#
|
275
|
+
# @raise [RdkafkaError] When getting the positions fails.
|
276
|
+
#
|
277
|
+
# @return [TopicPartitionList]
|
278
|
+
def position(list=nil)
|
279
|
+
if list.nil?
|
280
|
+
list = assignment
|
281
|
+
elsif !list.is_a?(TopicPartitionList)
|
282
|
+
raise TypeError.new("list has to be nil or a TopicPartitionList")
|
283
|
+
end
|
284
|
+
|
285
|
+
tpl = list.to_native_tpl
|
286
|
+
|
287
|
+
response = @native_kafka.with_inner do |inner|
|
288
|
+
Rdkafka::Bindings.rd_kafka_position(inner, tpl)
|
289
|
+
end
|
290
|
+
|
291
|
+
Rdkafka::RdkafkaError.validate!(response)
|
292
|
+
|
293
|
+
TopicPartitionList.from_native_tpl(tpl)
|
294
|
+
end
|
295
|
+
|
275
296
|
# Query broker for low (oldest/beginning) and high (newest/end) offsets for a partition.
|
276
297
|
#
|
277
298
|
# @param topic [String] The topic to query
|
278
299
|
# @param partition [Integer] The partition to query
|
279
300
|
# @param timeout_ms [Integer] The timeout for querying the broker
|
280
|
-
#
|
281
|
-
# @raise [RdkafkaError] When querying the broker fails.
|
282
|
-
#
|
283
301
|
# @return [Integer] The low and high watermark
|
302
|
+
# @raise [RdkafkaError] When querying the broker fails.
|
284
303
|
def query_watermark_offsets(topic, partition, timeout_ms=200)
|
285
304
|
closed_consumer_check(__method__)
|
286
305
|
|
@@ -297,9 +316,8 @@ module Rdkafka
|
|
297
316
|
timeout_ms,
|
298
317
|
)
|
299
318
|
end
|
300
|
-
|
301
|
-
|
302
|
-
end
|
319
|
+
|
320
|
+
Rdkafka::RdkafkaError.validate!(response, "Error querying watermark offsets for partition #{partition} of #{topic}")
|
303
321
|
|
304
322
|
return low.read_array_of_int64(1).first, high.read_array_of_int64(1).first
|
305
323
|
ensure
|
@@ -314,10 +332,9 @@ module Rdkafka
|
|
314
332
|
#
|
315
333
|
# @param topic_partition_list [TopicPartitionList] The list to calculate lag for.
|
316
334
|
# @param watermark_timeout_ms [Integer] The timeout for each query watermark call.
|
317
|
-
#
|
335
|
+
# @return [Hash<String, Hash<Integer, Integer>>] A hash containing all topics with the lag
|
336
|
+
# per partition
|
318
337
|
# @raise [RdkafkaError] When querying the broker fails.
|
319
|
-
#
|
320
|
-
# @return [Hash<String, Hash<Integer, Integer>>] A hash containing all topics with the lag per partition
|
321
338
|
def lag(topic_partition_list, watermark_timeout_ms=100)
|
322
339
|
out = {}
|
323
340
|
|
@@ -327,7 +344,7 @@ module Rdkafka
|
|
327
344
|
topic_out = {}
|
328
345
|
partitions.each do |p|
|
329
346
|
next if p.offset.nil?
|
330
|
-
|
347
|
+
_, high = query_watermark_offsets(
|
331
348
|
topic,
|
332
349
|
p.partition,
|
333
350
|
watermark_timeout_ms
|
@@ -366,10 +383,8 @@ module Rdkafka
|
|
366
383
|
# When using this `enable.auto.offset.store` should be set to `false` in the config.
|
367
384
|
#
|
368
385
|
# @param message [Rdkafka::Consumer::Message] The message which offset will be stored
|
369
|
-
#
|
370
|
-
# @raise [RdkafkaError] When storing the offset fails
|
371
|
-
#
|
372
386
|
# @return [nil]
|
387
|
+
# @raise [RdkafkaError] When storing the offset fails
|
373
388
|
def store_offset(message)
|
374
389
|
closed_consumer_check(__method__)
|
375
390
|
|
@@ -387,9 +402,10 @@ module Rdkafka
|
|
387
402
|
message.partition,
|
388
403
|
message.offset
|
389
404
|
)
|
390
|
-
|
391
|
-
|
392
|
-
|
405
|
+
|
406
|
+
Rdkafka::RdkafkaError.validate!(response)
|
407
|
+
|
408
|
+
nil
|
393
409
|
ensure
|
394
410
|
if native_topic && !native_topic.null?
|
395
411
|
Rdkafka::Bindings.rd_kafka_topic_destroy(native_topic)
|
@@ -400,10 +416,8 @@ module Rdkafka
|
|
400
416
|
# message at the given offset.
|
401
417
|
#
|
402
418
|
# @param message [Rdkafka::Consumer::Message] The message to which to seek
|
403
|
-
#
|
404
|
-
# @raise [RdkafkaError] When seeking fails
|
405
|
-
#
|
406
419
|
# @return [nil]
|
420
|
+
# @raise [RdkafkaError] When seeking fails
|
407
421
|
def seek(message)
|
408
422
|
closed_consumer_check(__method__)
|
409
423
|
|
@@ -422,9 +436,9 @@ module Rdkafka
|
|
422
436
|
message.offset,
|
423
437
|
0 # timeout
|
424
438
|
)
|
425
|
-
|
426
|
-
|
427
|
-
|
439
|
+
Rdkafka::RdkafkaError.validate!(response)
|
440
|
+
|
441
|
+
nil
|
428
442
|
ensure
|
429
443
|
if native_topic && !native_topic.null?
|
430
444
|
Rdkafka::Bindings.rd_kafka_topic_destroy(native_topic)
|
@@ -455,9 +469,7 @@ module Rdkafka
|
|
455
469
|
)
|
456
470
|
end
|
457
471
|
|
458
|
-
|
459
|
-
raise Rdkafka::RdkafkaError.new(response)
|
460
|
-
end
|
472
|
+
Rdkafka::RdkafkaError.validate!(response)
|
461
473
|
|
462
474
|
TopicPartitionList.from_native_tpl(tpl)
|
463
475
|
ensure
|
@@ -475,10 +487,8 @@ module Rdkafka
|
|
475
487
|
#
|
476
488
|
# @param list [TopicPartitionList,nil] The topic with partitions to commit
|
477
489
|
# @param async [Boolean] Whether to commit async or wait for the commit to finish
|
478
|
-
#
|
479
|
-
# @raise [RdkafkaError] When committing fails
|
480
|
-
#
|
481
490
|
# @return [nil]
|
491
|
+
# @raise [RdkafkaError] When committing fails
|
482
492
|
def commit(list=nil, async=false)
|
483
493
|
closed_consumer_check(__method__)
|
484
494
|
|
@@ -492,9 +502,10 @@ module Rdkafka
|
|
492
502
|
response = @native_kafka.with_inner do |inner|
|
493
503
|
Rdkafka::Bindings.rd_kafka_commit(inner, tpl, async)
|
494
504
|
end
|
495
|
-
|
496
|
-
|
497
|
-
|
505
|
+
|
506
|
+
Rdkafka::RdkafkaError.validate!(response)
|
507
|
+
|
508
|
+
nil
|
498
509
|
ensure
|
499
510
|
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(tpl) if tpl
|
500
511
|
end
|
@@ -503,10 +514,8 @@ module Rdkafka
|
|
503
514
|
# Poll for the next message on one of the subscribed topics
|
504
515
|
#
|
505
516
|
# @param timeout_ms [Integer] Timeout of this poll
|
506
|
-
#
|
507
|
-
# @raise [RdkafkaError] When polling fails
|
508
|
-
#
|
509
517
|
# @return [Message, nil] A message or nil if there was no new message within the timeout
|
518
|
+
# @raise [RdkafkaError] When polling fails
|
510
519
|
def poll(timeout_ms)
|
511
520
|
closed_consumer_check(__method__)
|
512
521
|
|
@@ -519,9 +528,9 @@ module Rdkafka
|
|
519
528
|
# Create struct wrapper
|
520
529
|
native_message = Rdkafka::Bindings::Message.new(message_ptr)
|
521
530
|
# Raise error if needed
|
522
|
-
|
523
|
-
|
524
|
-
|
531
|
+
|
532
|
+
Rdkafka::RdkafkaError.validate!(native_message[:err])
|
533
|
+
|
525
534
|
# Create a message to pass out
|
526
535
|
Rdkafka::Consumer::Message.new(native_message)
|
527
536
|
end
|
@@ -532,17 +541,40 @@ module Rdkafka
|
|
532
541
|
end
|
533
542
|
end
|
534
543
|
|
544
|
+
# Polls the main rdkafka queue (not the consumer one). Do **NOT** use it if `consumer_poll_set`
|
545
|
+
# was set to `true`.
|
546
|
+
#
|
547
|
+
# Events will cause application-provided callbacks to be called.
|
548
|
+
#
|
549
|
+
# Events (in the context of the consumer):
|
550
|
+
# - error callbacks
|
551
|
+
# - stats callbacks
|
552
|
+
# - any other callbacks supported by librdkafka that are not part of the consumer_poll, that
|
553
|
+
# would have a callback configured and activated.
|
554
|
+
#
|
555
|
+
# This method needs to be called at regular intervals to serve any queued callbacks waiting to
|
556
|
+
# be called. When in use, does **NOT** replace `#poll` but needs to run complementary with it.
|
557
|
+
#
|
558
|
+
# @param timeout_ms [Integer] poll timeout. If set to 0 will run async, when set to -1 will
|
559
|
+
# block until any events available.
|
560
|
+
#
|
561
|
+
# @note This method technically should be called `#poll` and the current `#poll` should be
|
562
|
+
# called `#consumer_poll` though we keep the current naming convention to make it backward
|
563
|
+
# compatible.
|
564
|
+
def events_poll(timeout_ms = 0)
|
565
|
+
@native_kafka.with_inner do |inner|
|
566
|
+
Rdkafka::Bindings.rd_kafka_poll(inner, timeout_ms)
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
535
570
|
# Poll for new messages and yield for each received one. Iteration
|
536
571
|
# will end when the consumer is closed.
|
537
572
|
#
|
538
|
-
# If `enable.partition.eof` is turned on in the config this will raise an
|
539
|
-
#
|
540
|
-
# using this method of iteration.
|
573
|
+
# If `enable.partition.eof` is turned on in the config this will raise an error when an eof is
|
574
|
+
# reached, so you probably want to disable that when using this method of iteration.
|
541
575
|
#
|
542
576
|
# @raise [RdkafkaError] When polling fails
|
543
|
-
#
|
544
577
|
# @yieldparam message [Message] Received message
|
545
|
-
#
|
546
578
|
# @return [nil]
|
547
579
|
def each
|
548
580
|
loop do
|
@@ -595,9 +627,7 @@ module Rdkafka
|
|
595
627
|
# that you may or may not see again.
|
596
628
|
#
|
597
629
|
# @param max_items [Integer] Maximum size of the yielded array of messages
|
598
|
-
#
|
599
630
|
# @param bytes_threshold [Integer] Threshold number of total message bytes in the yielded array of messages
|
600
|
-
#
|
601
631
|
# @param timeout_ms [Integer] max time to wait for up to max_items
|
602
632
|
#
|
603
633
|
# @raise [RdkafkaError] When polling fails
|
@@ -644,10 +674,6 @@ module Rdkafka
|
|
644
674
|
end
|
645
675
|
|
646
676
|
private
|
647
|
-
def monotonic_now
|
648
|
-
# needed because Time.now can go backwards
|
649
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
650
|
-
end
|
651
677
|
|
652
678
|
def closed_consumer_check(method)
|
653
679
|
raise Rdkafka::ClosedConsumerError.new(method) if closed?
|
data/lib/rdkafka/error.rb
CHANGED
@@ -18,12 +18,59 @@ module Rdkafka
|
|
18
18
|
# @return [String]
|
19
19
|
attr_reader :broker_message
|
20
20
|
|
21
|
+
class << self
|
22
|
+
def build_from_c(response_ptr, message_prefix = nil, broker_message: nil)
|
23
|
+
code = Rdkafka::Bindings.rd_kafka_error_code(response_ptr)
|
24
|
+
|
25
|
+
return false if code.zero?
|
26
|
+
|
27
|
+
message = broker_message || Rdkafka::Bindings.rd_kafka_err2str(code)
|
28
|
+
fatal = !Rdkafka::Bindings.rd_kafka_error_is_fatal(response_ptr).zero?
|
29
|
+
retryable = !Rdkafka::Bindings.rd_kafka_error_is_retriable(response_ptr).zero?
|
30
|
+
abortable = !Rdkafka::Bindings.rd_kafka_error_txn_requires_abort(response_ptr).zero?
|
31
|
+
|
32
|
+
Rdkafka::Bindings.rd_kafka_error_destroy(response_ptr)
|
33
|
+
|
34
|
+
new(
|
35
|
+
code,
|
36
|
+
message_prefix,
|
37
|
+
broker_message: message,
|
38
|
+
fatal: fatal,
|
39
|
+
retryable: retryable,
|
40
|
+
abortable: abortable
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def build(response_ptr_or_code, message_prefix = nil, broker_message: nil)
|
45
|
+
if response_ptr_or_code.is_a?(Integer)
|
46
|
+
response_ptr_or_code.zero? ? false : new(response_ptr_or_code, message_prefix, broker_message: broker_message)
|
47
|
+
else
|
48
|
+
build_from_c(response_ptr_or_code, message_prefix)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate!(response_ptr_or_code, message_prefix = nil, broker_message: nil)
|
53
|
+
error = build(response_ptr_or_code, message_prefix, broker_message: broker_message)
|
54
|
+
error ? raise(error) : false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
21
58
|
# @private
|
22
|
-
def initialize(
|
59
|
+
def initialize(
|
60
|
+
response,
|
61
|
+
message_prefix=nil,
|
62
|
+
broker_message: nil,
|
63
|
+
fatal: false,
|
64
|
+
retryable: false,
|
65
|
+
abortable: false
|
66
|
+
)
|
23
67
|
raise TypeError.new("Response has to be an integer") unless response.is_a? Integer
|
24
68
|
@rdkafka_response = response
|
25
69
|
@message_prefix = message_prefix
|
26
70
|
@broker_message = broker_message
|
71
|
+
@fatal = fatal
|
72
|
+
@retryable = retryable
|
73
|
+
@abortable = abortable
|
27
74
|
end
|
28
75
|
|
29
76
|
# This error's code, for example `:partition_eof`, `:msg_size_too_large`.
|
@@ -58,6 +105,18 @@ module Rdkafka
|
|
58
105
|
def ==(another_error)
|
59
106
|
another_error.is_a?(self.class) && (self.to_s == another_error.to_s)
|
60
107
|
end
|
108
|
+
|
109
|
+
def fatal?
|
110
|
+
@fatal
|
111
|
+
end
|
112
|
+
|
113
|
+
def retryable?
|
114
|
+
@retryable
|
115
|
+
end
|
116
|
+
|
117
|
+
def abortable?
|
118
|
+
@abortable
|
119
|
+
end
|
61
120
|
end
|
62
121
|
|
63
122
|
# Error with topic partition list returned by the underlying rdkafka library.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rdkafka
|
4
|
+
# Namespace for some small utilities used in multiple components
|
5
|
+
module Helpers
|
6
|
+
# Time related methods used across Karafka
|
7
|
+
module Time
|
8
|
+
# @return [Float] current monotonic time in seconds with microsecond precision
|
9
|
+
def monotonic_now
|
10
|
+
::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/rdkafka/metadata.rb
CHANGED
@@ -29,8 +29,7 @@ module Rdkafka
|
|
29
29
|
# Retrieve the Metadata
|
30
30
|
result = Rdkafka::Bindings.rd_kafka_metadata(native_client, topic_flag, native_topic, ptr, timeout_ms)
|
31
31
|
|
32
|
-
|
33
|
-
raise Rdkafka::RdkafkaError.new(result) unless result.zero?
|
32
|
+
Rdkafka::RdkafkaError.validate!(result)
|
34
33
|
|
35
34
|
metadata_from_native(ptr.read_pointer)
|
36
35
|
rescue ::Rdkafka::RdkafkaError => e
|
@@ -58,11 +57,12 @@ module Rdkafka
|
|
58
57
|
|
59
58
|
@topics = Array.new(metadata[:topics_count]) do |i|
|
60
59
|
topic = TopicMetadata.new(metadata[:topics_metadata] + (i * TopicMetadata.size))
|
61
|
-
|
60
|
+
|
61
|
+
RdkafkaError.validate!(topic[:rd_kafka_resp_err])
|
62
62
|
|
63
63
|
partitions = Array.new(topic[:partition_count]) do |j|
|
64
64
|
partition = PartitionMetadata.new(topic[:partitions_metadata] + (j * PartitionMetadata.size))
|
65
|
-
|
65
|
+
RdkafkaError.validate!(partition[:rd_kafka_resp_err])
|
66
66
|
partition.to_h
|
67
67
|
end
|
68
68
|
topic.to_h.merge!(partitions: partitions)
|
data/lib/rdkafka/native_kafka.rb
CHANGED
@@ -4,8 +4,9 @@ module Rdkafka
|
|
4
4
|
# @private
|
5
5
|
# A wrapper around a native kafka that polls and cleanly exits
|
6
6
|
class NativeKafka
|
7
|
-
def initialize(inner, run_polling_thread:)
|
7
|
+
def initialize(inner, run_polling_thread:, opaque:)
|
8
8
|
@inner = inner
|
9
|
+
@opaque = opaque
|
9
10
|
# Lock around external access
|
10
11
|
@access_mutex = Mutex.new
|
11
12
|
# Lock around internal polling
|
@@ -27,6 +28,9 @@ module Rdkafka
|
|
27
28
|
# counter for operations in progress using inner
|
28
29
|
@operations_in_progress = 0
|
29
30
|
|
31
|
+
# Trigger initial poll to make sure oauthbearer cb and other initial cb are handled
|
32
|
+
Rdkafka::Bindings.rd_kafka_poll(inner, 0)
|
33
|
+
|
30
34
|
if run_polling_thread
|
31
35
|
# Start thread to poll client for delivery callbacks,
|
32
36
|
# not used in consumer.
|
@@ -109,6 +113,7 @@ module Rdkafka
|
|
109
113
|
|
110
114
|
Rdkafka::Bindings.rd_kafka_destroy(@inner)
|
111
115
|
@inner = nil
|
116
|
+
@opaque = nil
|
112
117
|
end
|
113
118
|
end
|
114
119
|
end
|
@@ -18,7 +18,22 @@ module Rdkafka
|
|
18
18
|
|
19
19
|
# @return [DeliveryReport] a report on the delivery of the message
|
20
20
|
def create_result
|
21
|
-
|
21
|
+
if self[:response] == 0
|
22
|
+
DeliveryReport.new(
|
23
|
+
self[:partition],
|
24
|
+
self[:offset],
|
25
|
+
self[:topic_name].read_string
|
26
|
+
)
|
27
|
+
else
|
28
|
+
DeliveryReport.new(
|
29
|
+
self[:partition],
|
30
|
+
self[:offset],
|
31
|
+
# For part of errors, we will not get a topic name reference and in cases like this
|
32
|
+
# we should not return it
|
33
|
+
self[:topic_name].null? ? nil : self[:topic_name].read_string,
|
34
|
+
Rdkafka::RdkafkaError.build(self[:response])
|
35
|
+
)
|
36
|
+
end
|
22
37
|
end
|
23
38
|
end
|
24
39
|
end
|
@@ -12,8 +12,9 @@ module Rdkafka
|
|
12
12
|
# @return [Integer]
|
13
13
|
attr_reader :offset
|
14
14
|
|
15
|
-
# The name of the topic this message was produced to
|
16
|
-
#
|
15
|
+
# The name of the topic this message was produced to or nil in case delivery failed and we
|
16
|
+
# we not able to get the topic reference
|
17
|
+
# @return [String, nil]
|
17
18
|
attr_reader :topic_name
|
18
19
|
|
19
20
|
# Error in case happen during produce.
|