waterdrop 2.6.1 → 2.6.2

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: 1ed8c6f17cd730ab82df21e696e472c51dd51379acf757f735d43de98c00dead
4
+ data.tar.gz: 10f8b0d7bd64c26ba9b76c9edb76cf59f871cf44adbde2198907856f7b761ea4
5
5
  SHA512:
6
- metadata.gz: e0eab9080a356e2d3ee5c2c68d48484057d4ed77aebcc9eda0a88c28f5e4da7812072686b60c12eb6f2536a1c4daa8b427844f2abbeccbfaf22f18f597702707
7
- data.tar.gz: 462fbb70e2794703b5d09b29b94c1c1c6b8e8642beb407f1dee638be66913a07af8c92114d129d1c85ad8c8f03e7d1ea776be42b0d0daa37b801aba607d40cf4
6
+ metadata.gz: a41f9a5e1ef30c69221615552f48bad03099697d27a1e405f90ab189f6c21a33dedc6382c864d4790a22d798c64023a1802597f8ce255214d077de0ebcd5028b
7
+ data.tar.gz: b21a71b53e188fd58ce8800bc23548cc3bbc0a876fe4aa8d9c67107b0e90ddfd6484c4e534137b63e4bb45d5760460ae4b7df79233d6a2acc85ba00d45a55e2a
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # WaterDrop changelog
2
2
 
3
+ ### 2.6.2 (2023-06-21)
4
+ - [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.
5
+ - [Refactor] Make private methods private.
6
+ - [Refactor] Validate that producer is not closed only when attempting to produce.
7
+ - [Refactor] Improve one 5 minute long spec to run in 10 seconds.
8
+ - [Refactor] clear client assignment after closing.
9
+
3
10
  ### 2.6.1 (2023-06-19)
4
11
  - [Refactor] Remove no longer needed patches.
5
12
  - [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,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- waterdrop (2.6.1)
4
+ waterdrop (2.6.2)
5
5
  karafka-core (>= 2.1.0, < 3.0.0)
6
6
  zeitwerk (~> 2.3)
7
7
 
@@ -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 = 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.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 += 1
209
+ else
210
+ @operating_mutex.synchronize { @operations_in_progress += 1 }
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 -= 1
232
252
  retry
253
+ ensure
254
+ @operations_in_progress -= 1
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.2'
7
7
  end
data.tar.gz.sig CHANGED
Binary file
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.2
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-21 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: karafka-core
metadata.gz.sig CHANGED
@@ -1,4 +1 @@
1
- T��:�h�ĎY��D
2
- C��4U9L��"tw
3
- �h����Al�� �T�:�-�m�SI��O��O���7V��I�gu�y$��2B�
4
- E=]�'},�G�|4a3���Q�Vk�i�4���=�k� �qb�h�e�P��b��l��(�8���0�I~��I4�Ŭ�I_ʏ^U8�{0� ��A{99 ���v��oeP�ܪ*z�� ��:k8VrB�fɹ����.��n����ࢀo���+�G6A���_}��l3�AJ�� �+Ul�SD��H�ۯ �<>�I�%�WІ^wɔ*�M�s�f`�wk=���'hF�m��+��huYyu0�}�2y�rq
1
+ E���y���!+t �V� ����5cK|��3��=�$š�x�3KN$ R<�T���=�{60�-�V����=���6���w�}�Ff%r�Z��������s�P��X��)�]��