waterdrop 2.6.1 → 2.6.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: 2150248405c747e29acb8e31207be9dc0c7c262916f003af9c55208ee3675d3d
4
- data.tar.gz: 0c920351ac4a40db3a0c57e8f4c12fa6f3c75ee197b9696c5b6464a35c1a8889
3
+ metadata.gz: f051a62baab08b5b23bb85a5b2264f3b33bebb77c0f3628ed90eda5eda8c22f2
4
+ data.tar.gz: 9a5f27b24bee02bb2efcaeec926a8568c540c420c77cf1c9a06a6d72fcf496b1
5
5
  SHA512:
6
- metadata.gz: e0eab9080a356e2d3ee5c2c68d48484057d4ed77aebcc9eda0a88c28f5e4da7812072686b60c12eb6f2536a1c4daa8b427844f2abbeccbfaf22f18f597702707
7
- data.tar.gz: 462fbb70e2794703b5d09b29b94c1c1c6b8e8642beb407f1dee638be66913a07af8c92114d129d1c85ad8c8f03e7d1ea776be42b0d0daa37b801aba607d40cf4
6
+ metadata.gz: 7fd5cd82e391ad95e9c48b4e6794ad6b4e0715b6f4a64e838c676064b96e22c2c0a0cea1f18e4131c5dc60ae33923b943d2828278404038f5f7a79b754cb6e37
7
+ data.tar.gz: 004d5f3fdbbe48733ba47f132e12dcf1bd3ab5e0705181825f8e93b207e12b955b97cf6c283dcb58049153dd3325dd3ea655130e60982d0300ec309460e0d583
checksums.yaml.gz.sig CHANGED
@@ -1,2 +1,4 @@
1
- ����[�N,Lb n���$�EV��)7g��$��6h�2@MӖn���X�H!��A����B�G�z&gkP߶ꮐ4����)��k��e%���eJ]#�D�3�*p���<�m_����k�I���yz-��v�ӷ�
2
- ��B*k6՝��Y!�^� ��AUr�C44ZD����G�����'� ��Z]�#DMͽ��S�=�]�����ykrM4����=��"��X�0k��<�D >��%��{�c1;(�Rʩ}�Gf�m�'�a�� 9
1
+ �N>�c����(P}cRMo4xB�=_qQ`��YG��+�vX�
2
+ ��+rH�AT�Wq��\�����]h3�X��f��=�'{��Cᮄ��hRp8Ҵ e8H=D��3�{y;����/�Bq km�+�q�?'6�*q�S| ,ԡltg��� �+�����"��8�\�37#߀)PZ��(����7�����*Y&3
3
+ !J�5F�%��VҾ5�s^q�6dy���(�4�^�m+�?�x�g  )�ގt���9�u��7Q �7o�$�����k�
4
+ �����a���+vT�g7��]o,f�&�X)�?
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # WaterDrop changelog
2
2
 
3
+ ### 2.6.3 (2023-06-28)
4
+ - [Change] Use `Concurrent::AtomicFixnum` to track operations in progress to prevent potential race conditions on JRuby and TruffleRuby (not yet supported but this is for future usage).
5
+ - [Change] Require `karafka-rdkafka` `>= 0.13.2`.
6
+ - [Change] Require 'karafka-core' `>= 2.1.1`
7
+
8
+ ### 2.6.2 (2023-06-21)
9
+ - [Refactor] Introduce a counter-based locking approach to make sure, that we close the producer safely but at the same time not to limit messages production with producing lock.
10
+ - [Refactor] Make private methods private.
11
+ - [Refactor] Validate that producer is not closed only when attempting to produce.
12
+ - [Refactor] Improve one 5 minute long spec to run in 10 seconds.
13
+ - [Refactor] clear client assignment after closing.
14
+
3
15
  ### 2.6.1 (2023-06-19)
4
16
  - [Refactor] Remove no longer needed patches.
5
17
  - [Fix] Fork detection on a short lived processes seems to fail. Clear the used parent process client reference not to close it in the finalizer (#356).
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- waterdrop (2.6.1)
5
- karafka-core (>= 2.1.0, < 3.0.0)
4
+ waterdrop (2.6.3)
5
+ karafka-core (>= 2.1.1, < 3.0.0)
6
6
  zeitwerk (~> 2.3)
7
7
 
8
8
  GEM
@@ -22,10 +22,10 @@ GEM
22
22
  ffi (1.15.5)
23
23
  i18n (1.14.1)
24
24
  concurrent-ruby (~> 1.0)
25
- karafka-core (2.1.0)
25
+ karafka-core (2.1.1)
26
26
  concurrent-ruby (>= 1.1)
27
- karafka-rdkafka (>= 0.13.0, < 0.14.0)
28
- karafka-rdkafka (0.13.0)
27
+ karafka-rdkafka (>= 0.13.1, < 0.14.0)
28
+ karafka-rdkafka (0.13.2)
29
29
  ffi (~> 1.15)
30
30
  mini_portile2 (~> 2.6)
31
31
  rake (> 12)
@@ -24,8 +24,8 @@ module WaterDrop
24
24
  # "Produces" message to Kafka: it acknowledges it locally, adds it to the internal buffer
25
25
  # @param message [Hash] `WaterDrop::Producer#produce_sync` message hash
26
26
  def produce(message)
27
- topic = message.fetch(:topic) { raise ArgumentError, ':topic is missing' }
28
- @topics[topic] << message
27
+ # We pre-validate the message payload, so topic is ensured to be present
28
+ @topics[message.fetch(:topic)] << message
29
29
  @messages << message
30
30
  SyncResponse.new
31
31
  end
@@ -14,8 +14,6 @@ module WaterDrop
14
14
  # @raise [Errors::MessageInvalidError] When provided message details are invalid and the
15
15
  # message could not be sent to Kafka
16
16
  def produce_async(message)
17
- ensure_active!
18
-
19
17
  message = middleware.run(message)
20
18
  validate_message!(message)
21
19
 
@@ -49,8 +47,6 @@ module WaterDrop
49
47
  # @raise [Errors::MessageInvalidError] When any of the provided messages details are invalid
50
48
  # and the message could not be sent to Kafka
51
49
  def produce_many_async(messages)
52
- ensure_active!
53
-
54
50
  dispatched = []
55
51
  messages = middleware.run_many(messages)
56
52
  messages.each { |message| validate_message!(message) }
@@ -11,6 +11,7 @@ module WaterDrop
11
11
  # message could not be sent to Kafka
12
12
  def buffer(message)
13
13
  ensure_active!
14
+
14
15
  message = middleware.run(message)
15
16
  validate_message!(message)
16
17
 
@@ -49,8 +50,6 @@ module WaterDrop
49
50
  # @return [Array<Rdkafka::Producer::DeliveryHandle>] delivery handles for messages that were
50
51
  # flushed
51
52
  def flush_async
52
- ensure_active!
53
-
54
53
  @monitor.instrument(
55
54
  'buffer.flushed_async',
56
55
  producer_id: id,
@@ -62,8 +61,6 @@ module WaterDrop
62
61
  # @return [Array<Rdkafka::Producer::DeliveryReport>] delivery reports for messages that were
63
62
  # flushed
64
63
  def flush_sync
65
- ensure_active!
66
-
67
64
  @monitor.instrument(
68
65
  'buffer.flushed_sync',
69
66
  producer_id: id,
@@ -16,8 +16,6 @@ module WaterDrop
16
16
  # @raise [Errors::MessageInvalidError] When provided message details are invalid and the
17
17
  # message could not be sent to Kafka
18
18
  def produce_sync(message)
19
- ensure_active!
20
-
21
19
  message = middleware.run(message)
22
20
  validate_message!(message)
23
21
 
@@ -55,8 +53,6 @@ module WaterDrop
55
53
  # @raise [Errors::MessageInvalidError] When any of the provided messages details are invalid
56
54
  # and the message could not be sent to Kafka
57
55
  def produce_many_sync(messages)
58
- ensure_active! unless @closing_thread_id && @closing_thread_id == Thread.current.object_id
59
-
60
56
  messages = middleware.run_many(messages)
61
57
  messages.each { |message| validate_message!(message) }
62
58
 
@@ -34,9 +34,10 @@ module WaterDrop
34
34
  # @param block [Proc] configuration block
35
35
  # @return [Producer] producer instance
36
36
  def initialize(&block)
37
+ @operations_in_progress = Concurrent::AtomicFixnum.new(0)
37
38
  @buffer_mutex = Mutex.new
38
39
  @connecting_mutex = Mutex.new
39
- @closing_mutex = Mutex.new
40
+ @operating_mutex = Mutex.new
40
41
 
41
42
  @status = Status.new
42
43
  @messages = Concurrent::Array.new
@@ -118,7 +119,7 @@ module WaterDrop
118
119
 
119
120
  # Flushes the buffers in a sync way and closes the producer
120
121
  def close
121
- @closing_mutex.synchronize do
122
+ @operating_mutex.synchronize do
122
123
  return unless @status.active?
123
124
 
124
125
  @monitor.instrument(
@@ -135,6 +136,10 @@ module WaterDrop
135
136
  # producer for final flush of buffers.
136
137
  @closing_thread_id = Thread.current.object_id
137
138
 
139
+ # Wait until all the outgoing operations are done. Only when no one is using the
140
+ # underlying client running operations we can close
141
+ sleep(0.001) until @operations_in_progress.value.zero?
142
+
138
143
  # Flush has its own buffer mutex but even if it is blocked, flushing can still happen
139
144
  # as we close the client after the flushing (even if blocked by the mutex)
140
145
  flush(true)
@@ -143,7 +148,10 @@ module WaterDrop
143
148
  # It is safe to run it several times but not exactly the same moment
144
149
  # We also mark it as closed only if it was connected, if not, it would trigger a new
145
150
  # connection that anyhow would be immediately closed
146
- client.close if @client
151
+ if @client
152
+ client.close
153
+ @client = nil
154
+ end
147
155
 
148
156
  # Remove callbacks runners that were registered
149
157
  ::Karafka::Core::Instrumentation.statistics_callbacks.delete(@id)
@@ -154,13 +162,17 @@ module WaterDrop
154
162
  end
155
163
  end
156
164
 
165
+ private
166
+
157
167
  # Ensures that we don't run any operations when the producer is not configured or when it
158
168
  # was already closed
159
169
  def ensure_active!
160
170
  return if @status.active?
171
+ return if @status.closing? && @operating_mutex.owned?
161
172
 
162
173
  raise Errors::ProducerNotConfiguredError, id if @status.initial?
163
- raise Errors::ProducerClosedError, id if @status.closing? || @status.closed?
174
+ raise Errors::ProducerClosedError, id if @status.closing?
175
+ raise Errors::ProducerClosedError, id if @status.closed?
164
176
 
165
177
  # This should never happen
166
178
  raise Errors::StatusInvalidError, [id, @status.to_s]
@@ -184,14 +196,21 @@ module WaterDrop
184
196
  )
185
197
  end
186
198
 
187
- private
188
-
189
199
  # Runs the client produce method with a given message
190
200
  #
191
201
  # @param message [Hash] message we want to send
192
202
  def produce(message)
193
203
  produce_time ||= monotonic_now
194
204
 
205
+ # This can happen only during flushing on closing, in case like this we don't have to
206
+ # synchronize because we already own the lock
207
+ if @operating_mutex.owned?
208
+ @operations_in_progress.increment
209
+ else
210
+ @operating_mutex.synchronize { @operations_in_progress.increment }
211
+ ensure_active!
212
+ end
213
+
195
214
  client.produce(**message)
196
215
  rescue SUPPORTED_FLOW_ERRORS.first => e
197
216
  # Unless we want to wait and retry and it's a full queue, we raise normally
@@ -229,7 +248,10 @@ module WaterDrop
229
248
  sleep @config.wait_backoff_on_queue_full
230
249
  end
231
250
 
251
+ @operations_in_progress.decrement
232
252
  retry
253
+ ensure
254
+ @operations_in_progress.decrement
233
255
  end
234
256
  end
235
257
  end
@@ -3,5 +3,5 @@
3
3
  # WaterDrop library
4
4
  module WaterDrop
5
5
  # Current WaterDrop version
6
- VERSION = '2.6.1'
6
+ VERSION = '2.6.3'
7
7
  end
data/lib/waterdrop.rb CHANGED
@@ -9,6 +9,7 @@
9
9
  securerandom
10
10
  karafka-core
11
11
  pathname
12
+ concurrent/atomic/atomic_fixnum
12
13
  ].each { |lib| require lib }
13
14
 
14
15
  # WaterDrop library
data/waterdrop.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.description = spec.summary
17
17
  spec.license = 'MIT'
18
18
 
19
- spec.add_dependency 'karafka-core', '>= 2.1.0', '< 3.0.0'
19
+ spec.add_dependency 'karafka-core', '>= 2.1.1', '< 3.0.0'
20
20
  spec.add_dependency 'zeitwerk', '~> 2.3'
21
21
 
22
22
  if $PROGRAM_NAME.end_with?('gem')
data.tar.gz.sig CHANGED
@@ -1,3 +1,4 @@
1
- =f��~�N��?bƉ�oߨ�b qc�}�ݵ =�#�L��nA�'�Q�o<Mw,���xY��rb�z�]�6�M������RV���\�[�|]�]��f�H�z8�O}���mK�
2
- ����Pע��Oeǩ��
3
- <+����݊'zDdv��o�;���<&8J,�8����A/��͔�=3rH��3��!+��U#��J�����
1
+ #�}��6���ӝߕ�4
2
+ �
3
+ 01\������� .)dF��JbvN,
4
+ ��Y,�e �i�i�g�Q&��
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: waterdrop
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.1
4
+ version: 2.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Mensfeld
@@ -35,7 +35,7 @@ cert_chain:
35
35
  Qf04B9ceLUaC4fPVEz10FyobjaFoY4i32xRto3XnrzeAgfEe4swLq8bQsR3w/EF3
36
36
  MGU0FeSV2Yj7Xc2x/7BzLK8xQn5l7Yy75iPF+KP3vVmDHnNl
37
37
  -----END CERTIFICATE-----
38
- date: 2023-06-19 00:00:00.000000000 Z
38
+ date: 2023-06-28 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.1.0
46
+ version: 2.1.1
47
47
  - - "<"
48
48
  - !ruby/object:Gem::Version
49
49
  version: 3.0.0
@@ -53,7 +53,7 @@ dependencies:
53
53
  requirements:
54
54
  - - ">="
55
55
  - !ruby/object:Gem::Version
56
- version: 2.1.0
56
+ version: 2.1.1
57
57
  - - "<"
58
58
  - !ruby/object:Gem::Version
59
59
  version: 3.0.0
metadata.gz.sig CHANGED
Binary file