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

Sign up to get free protection for your applications and to get access to all the features.
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