rdkafka 0.13.0.beta.7 → 0.13.0.beta.8

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: 5a4ea932db3e81e325c31d9e1aedd5604eccc30d1faa865cac5986a66c59ddaa
4
- data.tar.gz: b8da648c6ac7f83ba48c7e19a391e918dc4ed7d9bdc6ab57d9479b43b34760e3
3
+ metadata.gz: e774c8eb7ac27fd5d89e3b28e5786bfbbc1354e7a35da0d89e7e1ebc488c0b80
4
+ data.tar.gz: d21b5a39de5fd22e38e9d2342a984c552b317d525a67d4128a9c78a07e0b1737
5
5
  SHA512:
6
- metadata.gz: f4f25d641d18a7a1f2b2b6bc3f56ae9a56c26212a46d809f3d97a02bc41bf4bc1094d208762d3c3e96087222fa4ed6dfeacf4fab3967c93fd02540f999678f1d
7
- data.tar.gz: 19f7832ccfce84daf5faca7eb3c74c37ab5dcdf7e60a40fed9cb10e99408a3baf61a310cdae9e63835b201b757428beb7b5c8f57cc1c82f6b99dd8b1bf280286
6
+ metadata.gz: 0cb979f4cc0a693f183e817fad944f8f24f09190ccd5d6363f3df9696441ef8b76056e05286f0214443095cd8b11b2abf9e3b8223d73a43bc09583dbab9b90dc
7
+ data.tar.gz: dded899763cf50da00fda25dcb03974946ccc0199eaececa2f20bc043971e3bf8a14c85610258f207424f8b76c69eac1a025f1e4b30297a2eedd4937ca705dee
@@ -27,9 +27,11 @@ module Rdkafka
27
27
  def close
28
28
  return if closed?
29
29
  ObjectSpace.undefine_finalizer(self)
30
- @native_kafka.with_inner do |inner|
30
+
31
+ @native_kafka.synchronize do |inner|
31
32
  Rdkafka::Bindings.rd_kafka_consumer_close(inner)
32
33
  end
34
+
33
35
  @native_kafka.close
34
36
  end
35
37
 
data/lib/rdkafka/error.rb CHANGED
@@ -92,4 +92,10 @@ module Rdkafka
92
92
  super("Illegal call to #{method.to_s} on a closed admin")
93
93
  end
94
94
  end
95
+
96
+ class ClosedInnerError < BaseError
97
+ def initialize
98
+ super("Illegal call to a closed inner librdkafka instance")
99
+ end
100
+ end
95
101
  end
@@ -10,6 +10,8 @@ module Rdkafka
10
10
  @access_mutex = Mutex.new
11
11
  # Lock around internal polling
12
12
  @poll_mutex = Mutex.new
13
+ # counter for operations in progress using inner
14
+ @operations_in_progress = 0
13
15
 
14
16
  if run_polling_thread
15
17
  # Start thread to poll client for delivery callbacks,
@@ -35,10 +37,26 @@ module Rdkafka
35
37
  end
36
38
 
37
39
  def with_inner
38
- return if @inner.nil?
40
+ if @access_mutex.owned?
41
+ @operations_in_progress += 1
42
+ else
43
+ @access_mutex.synchronize { @operations_in_progress += 1 }
44
+ end
45
+
46
+ @inner.nil? ? raise(ClosedInnerError) : yield(@inner)
47
+ ensure
48
+ @operations_in_progress -= 1
49
+ end
39
50
 
51
+ def synchronize(&block)
40
52
  @access_mutex.synchronize do
41
- yield @inner
53
+ # Wait for any commands using the inner to finish
54
+ # This can take a while on blocking operations like polling but is essential not to proceed
55
+ # with certain types of operations like resources destruction as it can cause the process
56
+ # to hang or crash
57
+ sleep(0.01) until @operations_in_progress.zero?
58
+
59
+ with_inner(&block)
42
60
  end
43
61
  end
44
62
 
@@ -53,31 +71,31 @@ module Rdkafka
53
71
  def close(object_id=nil)
54
72
  return if closed?
55
73
 
56
- @access_mutex.lock
74
+ synchronize do
75
+ # Indicate to the outside world that we are closing
76
+ @closing = true
57
77
 
58
- # Indicate to the outside world that we are closing
59
- @closing = true
78
+ if @polling_thread
79
+ # Indicate to polling thread that we're closing
80
+ @polling_thread[:closing] = true
60
81
 
61
- if @polling_thread
62
- # Indicate to polling thread that we're closing
63
- @polling_thread[:closing] = true
64
-
65
- # Wait for the polling thread to finish up,
66
- # this can be aborted in practice if this
67
- # code runs from a finalizer.
68
- @polling_thread.join
69
- end
82
+ # Wait for the polling thread to finish up,
83
+ # this can be aborted in practice if this
84
+ # code runs from a finalizer.
85
+ @polling_thread.join
86
+ end
70
87
 
71
- # Destroy the client after locking both mutexes
72
- @poll_mutex.lock
88
+ # Destroy the client after locking both mutexes
89
+ @poll_mutex.lock
73
90
 
74
- # This check prevents a race condition, where we would enter the close in two threads
75
- # and after unlocking the primary one that hold the lock but finished, ours would be unlocked
76
- # and would continue to run, trying to destroy inner twice
77
- return unless @inner
91
+ # This check prevents a race condition, where we would enter the close in two threads
92
+ # and after unlocking the primary one that hold the lock but finished, ours would be unlocked
93
+ # and would continue to run, trying to destroy inner twice
94
+ return unless @inner
78
95
 
79
- Rdkafka::Bindings.rd_kafka_destroy(@inner)
80
- @inner = nil
96
+ Rdkafka::Bindings.rd_kafka_destroy(@inner)
97
+ @inner = nil
98
+ end
81
99
  end
82
100
  end
83
101
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rdkafka
4
- VERSION = "0.13.0.beta.7"
4
+ VERSION = "0.13.0.beta.8"
5
5
  LIBRDKAFKA_VERSION = "2.0.2"
6
6
  LIBRDKAFKA_SOURCE_SHA256 = "f321bcb1e015a34114c83cf1aa7b99ee260236aab096b85c003170c90a47ca9d"
7
7
  end
@@ -286,6 +286,29 @@ describe Rdkafka::Consumer do
286
286
  consumer.poll(100)
287
287
  }.to raise_error(Rdkafka::ClosedConsumerError, /poll/)
288
288
  end
289
+
290
+ context 'when there are outgoing operations in other threads' do
291
+ it 'should wait and not crash' do
292
+ times = []
293
+
294
+ # Run a long running poll
295
+ thread = Thread.new do
296
+ times << Time.now
297
+ consumer.subscribe("empty_test_topic")
298
+ times << Time.now
299
+ consumer.poll(1_000)
300
+ times << Time.now
301
+ end
302
+
303
+ # Make sure it starts before we close
304
+ sleep(0.1)
305
+ consumer.close
306
+ close_time = Time.now
307
+ thread.join
308
+
309
+ times.each { |op_time| expect(op_time).to be < close_time }
310
+ end
311
+ end
289
312
  end
290
313
 
291
314
  describe "#commit, #committed and #store_offset" do
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.7
4
+ version: 0.13.0.beta.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thijs Cadier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-12 00:00:00.000000000 Z
11
+ date: 2023-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi