rdkafka 0.13.0.beta.2 → 0.13.0.beta.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eac016dc712d56e178c77a62f8af4e422319a783e80acbd7528453bfca6ca260
4
- data.tar.gz: 8a4ed8df1339e0e74c96b259431012465c499ae9e9c8c6db8ff751497e1e5c43
3
+ metadata.gz: 9db414f84847b884bded4eb7643ead52ee664256acdde47dcf7bb5e8421b5882
4
+ data.tar.gz: d696bce3413d5a591542e6bb1b7191acabd5b331e4115fb7a78b6d65320874d4
5
5
  SHA512:
6
- metadata.gz: e3167de231aaabdfa512cabef13a4ffaabcc94757a2b7d0f360ed27a9005a40da5bbb262dffc49bda03d11557eef63dcf6b9c010fb944cf41fcb06bb7531c3ee
7
- data.tar.gz: 8db04d46686505a9b1fef79c8544f3c27056ae5ff9e9eede9343d4f5cef4c63c844b9798011a5339ebbdf2cab883d1c3fd5df61842ea90c4862fa0d03dd88610
6
+ metadata.gz: cd209306c840710661108a357adbeec6a24cc1aa1a828959041a0810c25b19ddbb9b52442a69c389995361c96c075a9a572b532cc6ba97c70160d99db46f5d8d
7
+ data.tar.gz: 5cb50b3717ab7904d4d8afb46233f0435cf519511755ee5137ccdf638775947f23db3ff40ac1efcd0562a767e23f5a65224e8d59f3a753b33206253f9db4dfc6
data/lib/rdkafka/admin.rb CHANGED
@@ -18,11 +18,16 @@ module Rdkafka
18
18
 
19
19
  # Close this admin instance
20
20
  def close
21
+ return if closed?
21
22
  ObjectSpace.undefine_finalizer(self)
22
-
23
23
  @native_kafka.close
24
24
  end
25
25
 
26
+ # Whether this admin has closed
27
+ def closed?
28
+ @native_kafka.closed?
29
+ end
30
+
26
31
  # Create a topic with the given partition count and replication factor
27
32
  #
28
33
  # @raise [ConfigError] When the partition count or replication factor are out of valid range
@@ -149,7 +154,7 @@ module Rdkafka
149
154
 
150
155
  private
151
156
  def closed_admin_check(method)
152
- raise Rdkafka::ClosedAdminError.new(method) if @native_kafka.closed?
157
+ raise Rdkafka::ClosedAdminError.new(method) if closed?
153
158
  end
154
159
  end
155
160
  end
@@ -169,7 +169,9 @@ module Rdkafka
169
169
  ]
170
170
 
171
171
  attach_function :rd_kafka_new, [:kafka_type, :pointer, :pointer, :int], :pointer
172
- attach_function :rd_kafka_destroy, [:pointer], :void
172
+
173
+ RD_KAFKA_DESTROY_F_IMMEDIATE = 0x4
174
+ attach_function :rd_kafka_destroy_flags, [:pointer, :int], :void
173
175
 
174
176
  # Consumer
175
177
 
@@ -157,13 +157,14 @@ module Rdkafka
157
157
  Rdkafka::Bindings.rd_kafka_conf_set_rebalance_cb(config, Rdkafka::Bindings::RebalanceCallback)
158
158
  end
159
159
 
160
+ # Create native client
160
161
  kafka = native_kafka(config, :rd_kafka_consumer)
161
162
 
162
163
  # Redirect the main queue to the consumer
163
164
  Rdkafka::Bindings.rd_kafka_poll_set_consumer(kafka)
164
165
 
165
166
  # Return consumer with Kafka client
166
- Rdkafka::Consumer.new(kafka)
167
+ Rdkafka::Consumer.new(Rdkafka::NativeKafka.new(kafka, run_polling_thread: false))
167
168
  end
168
169
 
169
170
  # Create a producer with this configuration.
@@ -181,7 +182,7 @@ module Rdkafka
181
182
  Rdkafka::Bindings.rd_kafka_conf_set_dr_msg_cb(config, Rdkafka::Callbacks::DeliveryCallbackFunction)
182
183
  # Return producer with Kafka client
183
184
  partitioner_name = self[:partitioner] || self["partitioner"]
184
- Rdkafka::Producer.new(Rdkafka::NativeKafka.new(native_kafka(config, :rd_kafka_producer)), partitioner_name).tap do |producer|
185
+ Rdkafka::Producer.new(Rdkafka::NativeKafka.new(native_kafka(config, :rd_kafka_producer), run_polling_thread: true), partitioner_name).tap do |producer|
185
186
  opaque.producer = producer
186
187
  end
187
188
  end
@@ -196,7 +197,7 @@ module Rdkafka
196
197
  opaque = Opaque.new
197
198
  config = native_config(opaque)
198
199
  Rdkafka::Bindings.rd_kafka_conf_set_background_event_cb(config, Rdkafka::Callbacks::BackgroundEventCallbackFunction)
199
- Rdkafka::Admin.new(Rdkafka::NativeKafka.new(native_kafka(config, :rd_kafka_producer)))
200
+ Rdkafka::Admin.new(Rdkafka::NativeKafka.new(native_kafka(config, :rd_kafka_producer), run_polling_thread: true))
200
201
  end
201
202
 
202
203
  # Error that is returned by the underlying rdkafka error if an invalid configuration option is present.
@@ -26,15 +26,14 @@ module Rdkafka
26
26
  # @return [nil]
27
27
  def close
28
28
  return if closed?
29
-
30
- Rdkafka::Bindings.rd_kafka_consumer_close(@native_kafka)
31
- Rdkafka::Bindings.rd_kafka_destroy(@native_kafka)
32
- @native_kafka = nil
29
+ ObjectSpace.undefine_finalizer(self)
30
+ Rdkafka::Bindings.rd_kafka_consumer_close(@native_kafka.inner)
31
+ @native_kafka.close
33
32
  end
34
33
 
35
34
  # Whether this consumer has closed
36
35
  def closed?
37
- @native_kafka.nil?
36
+ @native_kafka.closed?
38
37
  end
39
38
 
40
39
  # Subscribe to one or more topics letting Kafka handle partition assignments.
@@ -55,7 +54,7 @@ module Rdkafka
55
54
  end
56
55
 
57
56
  # Subscribe to topic partition list and check this was successful
58
- response = Rdkafka::Bindings.rd_kafka_subscribe(@native_kafka, tpl)
57
+ response = Rdkafka::Bindings.rd_kafka_subscribe(@native_kafka.inner, tpl)
59
58
  if response != 0
60
59
  raise Rdkafka::RdkafkaError.new(response, "Error subscribing to '#{topics.join(', ')}'")
61
60
  end
@@ -71,7 +70,7 @@ module Rdkafka
71
70
  def unsubscribe
72
71
  closed_consumer_check(__method__)
73
72
 
74
- response = Rdkafka::Bindings.rd_kafka_unsubscribe(@native_kafka)
73
+ response = Rdkafka::Bindings.rd_kafka_unsubscribe(@native_kafka.inner)
75
74
  if response != 0
76
75
  raise Rdkafka::RdkafkaError.new(response)
77
76
  end
@@ -94,7 +93,7 @@ module Rdkafka
94
93
  tpl = list.to_native_tpl
95
94
 
96
95
  begin
97
- response = Rdkafka::Bindings.rd_kafka_pause_partitions(@native_kafka, tpl)
96
+ response = Rdkafka::Bindings.rd_kafka_pause_partitions(@native_kafka.inner, tpl)
98
97
 
99
98
  if response != 0
100
99
  list = TopicPartitionList.from_native_tpl(tpl)
@@ -122,7 +121,7 @@ module Rdkafka
122
121
  tpl = list.to_native_tpl
123
122
 
124
123
  begin
125
- response = Rdkafka::Bindings.rd_kafka_resume_partitions(@native_kafka, tpl)
124
+ response = Rdkafka::Bindings.rd_kafka_resume_partitions(@native_kafka.inner, tpl)
126
125
  if response != 0
127
126
  raise Rdkafka::RdkafkaError.new(response, "Error resume '#{list.to_h}'")
128
127
  end
@@ -140,7 +139,7 @@ module Rdkafka
140
139
  closed_consumer_check(__method__)
141
140
 
142
141
  ptr = FFI::MemoryPointer.new(:pointer)
143
- response = Rdkafka::Bindings.rd_kafka_subscription(@native_kafka, ptr)
142
+ response = Rdkafka::Bindings.rd_kafka_subscription(@native_kafka.inner, ptr)
144
143
 
145
144
  if response != 0
146
145
  raise Rdkafka::RdkafkaError.new(response)
@@ -170,7 +169,7 @@ module Rdkafka
170
169
  tpl = list.to_native_tpl
171
170
 
172
171
  begin
173
- response = Rdkafka::Bindings.rd_kafka_assign(@native_kafka, tpl)
172
+ response = Rdkafka::Bindings.rd_kafka_assign(@native_kafka.inner, tpl)
174
173
  if response != 0
175
174
  raise Rdkafka::RdkafkaError.new(response, "Error assigning '#{list.to_h}'")
176
175
  end
@@ -188,7 +187,7 @@ module Rdkafka
188
187
  closed_consumer_check(__method__)
189
188
 
190
189
  ptr = FFI::MemoryPointer.new(:pointer)
191
- response = Rdkafka::Bindings.rd_kafka_assignment(@native_kafka, ptr)
190
+ response = Rdkafka::Bindings.rd_kafka_assignment(@native_kafka.inner, ptr)
192
191
  if response != 0
193
192
  raise Rdkafka::RdkafkaError.new(response)
194
193
  end
@@ -227,7 +226,7 @@ module Rdkafka
227
226
  tpl = list.to_native_tpl
228
227
 
229
228
  begin
230
- response = Rdkafka::Bindings.rd_kafka_committed(@native_kafka, tpl, timeout_ms)
229
+ response = Rdkafka::Bindings.rd_kafka_committed(@native_kafka.inner, tpl, timeout_ms)
231
230
  if response != 0
232
231
  raise Rdkafka::RdkafkaError.new(response)
233
232
  end
@@ -253,7 +252,7 @@ module Rdkafka
253
252
  high = FFI::MemoryPointer.new(:int64, 1)
254
253
 
255
254
  response = Rdkafka::Bindings.rd_kafka_query_watermark_offsets(
256
- @native_kafka,
255
+ @native_kafka.inner,
257
256
  topic,
258
257
  partition,
259
258
  low,
@@ -307,7 +306,7 @@ module Rdkafka
307
306
  # @return [String, nil]
308
307
  def cluster_id
309
308
  closed_consumer_check(__method__)
310
- Rdkafka::Bindings.rd_kafka_clusterid(@native_kafka)
309
+ Rdkafka::Bindings.rd_kafka_clusterid(@native_kafka.inner)
311
310
  end
312
311
 
313
312
  # Returns this client's broker-assigned group member id
@@ -317,7 +316,7 @@ module Rdkafka
317
316
  # @return [String, nil]
318
317
  def member_id
319
318
  closed_consumer_check(__method__)
320
- Rdkafka::Bindings.rd_kafka_memberid(@native_kafka)
319
+ Rdkafka::Bindings.rd_kafka_memberid(@native_kafka.inner)
321
320
  end
322
321
 
323
322
  # Store offset of a message to be used in the next commit of this consumer
@@ -335,7 +334,7 @@ module Rdkafka
335
334
  # rd_kafka_offset_store is one of the few calls that does not support
336
335
  # a string as the topic, so create a native topic for it.
337
336
  native_topic = Rdkafka::Bindings.rd_kafka_topic_new(
338
- @native_kafka,
337
+ @native_kafka.inner,
339
338
  message.topic,
340
339
  nil
341
340
  )
@@ -367,7 +366,7 @@ module Rdkafka
367
366
  # rd_kafka_offset_store is one of the few calls that does not support
368
367
  # a string as the topic, so create a native topic for it.
369
368
  native_topic = Rdkafka::Bindings.rd_kafka_topic_new(
370
- @native_kafka,
369
+ @native_kafka.inner,
371
370
  message.topic,
372
371
  nil
373
372
  )
@@ -411,7 +410,7 @@ module Rdkafka
411
410
  tpl = list ? list.to_native_tpl : nil
412
411
 
413
412
  begin
414
- response = Rdkafka::Bindings.rd_kafka_commit(@native_kafka, tpl, async)
413
+ response = Rdkafka::Bindings.rd_kafka_commit(@native_kafka.inner, tpl, async)
415
414
  if response != 0
416
415
  raise Rdkafka::RdkafkaError.new(response)
417
416
  end
@@ -430,7 +429,7 @@ module Rdkafka
430
429
  def poll(timeout_ms)
431
430
  closed_consumer_check(__method__)
432
431
 
433
- message_ptr = Rdkafka::Bindings.rd_kafka_consumer_poll(@native_kafka, timeout_ms)
432
+ message_ptr = Rdkafka::Bindings.rd_kafka_consumer_poll(@native_kafka.inner, timeout_ms)
434
433
  if message_ptr.null?
435
434
  nil
436
435
  else
@@ -445,7 +444,7 @@ module Rdkafka
445
444
  end
446
445
  ensure
447
446
  # Clean up rdkafka message if there is one
448
- if !message_ptr.nil? && !message_ptr.null?
447
+ if message_ptr && !message_ptr.null?
449
448
  Rdkafka::Bindings.rd_kafka_message_destroy(message_ptr)
450
449
  end
451
450
  end
@@ -4,21 +4,26 @@ 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)
7
+ def initialize(inner, run_polling_thread:)
8
8
  @inner = inner
9
9
 
10
- # Start thread to poll client for delivery callbacks
11
- @polling_thread = Thread.new do
12
- loop do
13
- Rdkafka::Bindings.rd_kafka_poll(inner, 250)
14
- # Exit thread if closing and the poll queue is empty
15
- if Thread.current[:closing] && Rdkafka::Bindings.rd_kafka_outq_len(inner) == 0
16
- break
10
+ if run_polling_thread
11
+ # Start thread to poll client for delivery callbacks,
12
+ # not used in consumer.
13
+ @polling_thread = Thread.new do
14
+ loop do
15
+ Rdkafka::Bindings.rd_kafka_poll(inner, 250)
16
+ # Exit thread if closing and the poll queue is empty
17
+ if Thread.current[:closing] && Rdkafka::Bindings.rd_kafka_outq_len(inner) == 0
18
+ break
19
+ end
17
20
  end
18
21
  end
22
+ @polling_thread.abort_on_exception = true
23
+ @polling_thread[:closing] = false
19
24
  end
20
- @polling_thread.abort_on_exception = true
21
- @polling_thread[:closing] = false
25
+
26
+ @closing = false
22
27
  end
23
28
 
24
29
  def inner
@@ -30,22 +35,27 @@ module Rdkafka
30
35
  end
31
36
 
32
37
  def closed?
33
- @inner.nil?
38
+ @closing || @inner.nil?
34
39
  end
35
40
 
36
41
  def close(object_id=nil)
37
42
  return if closed?
38
43
 
39
- # Flush outstanding activity
40
- Rdkafka::Bindings.rd_kafka_flush(@inner, 30 * 1000)
41
-
42
- # Indicate to polling thread that we're closing
43
- @polling_thread[:closing] = true
44
- # Wait for the polling thread to finish up
45
- @polling_thread.join
44
+ # Indicate to the outside world that we are closing
45
+ @closing = true
46
46
 
47
- Rdkafka::Bindings.rd_kafka_destroy(@inner)
47
+ if @polling_thread
48
+ # Indicate to polling thread that we're closing
49
+ @polling_thread[:closing] = true
50
+ # Wait for the polling thread to finish up
51
+ @polling_thread.join
52
+ end
48
53
 
54
+ # Destroy the client
55
+ Rdkafka::Bindings.rd_kafka_destroy_flags(
56
+ @inner,
57
+ Rdkafka::Bindings::RD_KAFKA_DESTROY_F_IMMEDIATE
58
+ )
49
59
  @inner = nil
50
60
  end
51
61
  end
@@ -40,11 +40,23 @@ module Rdkafka
40
40
 
41
41
  # Close this producer and wait for the internal poll queue to empty.
42
42
  def close
43
+ return if closed?
43
44
  ObjectSpace.undefine_finalizer(self)
44
-
45
45
  @native_kafka.close
46
46
  end
47
47
 
48
+ # Whether this producer has closed
49
+ def closed?
50
+ @native_kafka.closed?
51
+ end
52
+
53
+ # Wait until all outstanding producer requests are completed, with the given timeout
54
+ # in seconds. Call this before closing a producer to ensure delivery of all messages.
55
+ def flush(timeout_ms=5_000)
56
+ closed_producer_check(__method__)
57
+ Rdkafka::Bindings.rd_kafka_flush(@native_kafka.inner, timeout_ms)
58
+ end
59
+
48
60
  # Partition count for a given topic.
49
61
  # NOTE: If 'allow.auto.create.topics' is set to true in the broker, the topic will be auto-created after returning nil.
50
62
  #
@@ -173,7 +185,7 @@ module Rdkafka
173
185
 
174
186
  private
175
187
  def closed_producer_check(method)
176
- raise Rdkafka::ClosedProducerError.new(method) if @native_kafka.closed?
188
+ raise Rdkafka::ClosedProducerError.new(method) if closed?
177
189
  end
178
190
  end
179
191
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rdkafka
4
- VERSION = "0.13.0.beta.2"
4
+ VERSION = "0.13.0.beta.3"
5
5
  LIBRDKAFKA_VERSION = "1.9.2"
6
6
  LIBRDKAFKA_SOURCE_SHA256 = "3fba157a9f80a0889c982acdd44608be8a46142270a389008b22d921be1198ad"
7
7
  end
@@ -28,7 +28,7 @@ describe Rdkafka::Consumer::Message do
28
28
  end
29
29
 
30
30
  after(:each) do
31
- Rdkafka::Bindings.rd_kafka_destroy(native_client)
31
+ Rdkafka::Bindings.rd_kafka_destroy_flags(native_client, Rdkafka::Bindings::RD_KAFKA_DESTROY_F_IMMEDIATE)
32
32
  end
33
33
 
34
34
  subject { Rdkafka::Consumer::Message.new(native_message) }
@@ -10,7 +10,7 @@ describe Rdkafka::Metadata do
10
10
 
11
11
  after do
12
12
  Rdkafka::Bindings.rd_kafka_consumer_close(native_kafka)
13
- Rdkafka::Bindings.rd_kafka_destroy(native_kafka)
13
+ Rdkafka::Bindings.rd_kafka_destroy_flags(native_kafka, Rdkafka::Bindings::RD_KAFKA_DESTROY_F_IMMEDIATE)
14
14
  end
15
15
 
16
16
  context "passing in a topic name" do
@@ -8,12 +8,12 @@ describe Rdkafka::NativeKafka do
8
8
  let(:closing) { false }
9
9
  let(:thread) { double(Thread) }
10
10
 
11
- subject(:client) { described_class.new(native) }
11
+ subject(:client) { described_class.new(native, run_polling_thread: true) }
12
12
 
13
13
  before do
14
14
  allow(Rdkafka::Bindings).to receive(:rd_kafka_poll).with(instance_of(FFI::Pointer), 250).and_call_original
15
15
  allow(Rdkafka::Bindings).to receive(:rd_kafka_outq_len).with(instance_of(FFI::Pointer)).and_return(0).and_call_original
16
- allow(Rdkafka::Bindings).to receive(:rd_kafka_destroy)
16
+ allow(Rdkafka::Bindings).to receive(:rd_kafka_destroy_flags)
17
17
  allow(Thread).to receive(:new).and_return(thread)
18
18
 
19
19
  allow(thread).to receive(:[]=).with(:closing, anything)
@@ -53,6 +53,16 @@ describe Rdkafka::NativeKafka do
53
53
  expect(Rdkafka::Bindings).to receive(:rd_kafka_outq_len).with(native).at_least(:once)
54
54
  end
55
55
  end
56
+
57
+ context "if not enabled" do
58
+ subject(:client) { described_class.new(native, run_polling_thread: false) }
59
+
60
+ it "is not created" do
61
+ expect(Thread).not_to receive(:new)
62
+
63
+ client
64
+ end
65
+ end
56
66
  end
57
67
 
58
68
  def polling_loop_expects(&block)
@@ -76,7 +86,7 @@ describe Rdkafka::NativeKafka do
76
86
 
77
87
  context "and attempt to close" do
78
88
  it "calls the `destroy` binding" do
79
- expect(Rdkafka::Bindings).to receive(:rd_kafka_destroy).with(native)
89
+ expect(Rdkafka::Bindings).to receive(:rd_kafka_destroy_flags).with(native, Rdkafka::Bindings::RD_KAFKA_DESTROY_F_IMMEDIATE)
80
90
 
81
91
  client.close
82
92
  end
@@ -111,7 +121,7 @@ describe Rdkafka::NativeKafka do
111
121
 
112
122
  context "and attempt to close again" do
113
123
  it "does not call the `destroy` binding" do
114
- expect(Rdkafka::Bindings).not_to receive(:rd_kafka_destroy)
124
+ expect(Rdkafka::Bindings).not_to receive(:rd_kafka_destroy_flags)
115
125
 
116
126
  client.close
117
127
  end
@@ -185,7 +185,8 @@ describe Rdkafka::Producer do
185
185
  expect(report.partition).to eq 1
186
186
  expect(report.offset).to be >= 0
187
187
 
188
- # Close producer
188
+ # Flush and close producer
189
+ producer.flush
189
190
  producer.close
190
191
 
191
192
  # Consume message and verify its content
@@ -459,10 +460,10 @@ describe Rdkafka::Producer do
459
460
  # wait for and check the message in the main process.
460
461
  reader, writer = IO.pipe
461
462
 
462
- fork do
463
+ pid = fork do
463
464
  reader.close
464
465
 
465
- # Avoids sharing the socket between processes.
466
+ # Avoid sharing the client between processes.
466
467
  producer = rdkafka_producer_config.producer
467
468
 
468
469
  handle = producer.produce(
@@ -481,8 +482,10 @@ describe Rdkafka::Producer do
481
482
 
482
483
  writer.write(report_json)
483
484
  writer.close
485
+ producer.flush
484
486
  producer.close
485
487
  end
488
+ Process.wait(pid)
486
489
 
487
490
  writer.close
488
491
  report_hash = JSON.parse(reader.read)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rdkafka
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0.beta.2
4
+ version: 0.13.0.beta.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thijs Cadier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-12 00:00:00.000000000 Z
11
+ date: 2022-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi