waterdrop 2.6.1 → 2.6.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: 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