amqp-client 1.1.5 → 1.1.6

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: d3a9c50ecceb8a9d86bfea50d67957c1b063c47d35d85291b29e79b2631de262
4
- data.tar.gz: 055da4bc7ab51bac9f6839bf225c4f737b8aa766320609031ed68fa6b709cb88
3
+ metadata.gz: 10119835607b70ee73dd581f9bef3211a26fc18bb6fb7fa2f6e6bfe913076b16
4
+ data.tar.gz: a30989dab30c2dea294c0310bbfd211a36fa7453d935200c6b7783553f5e816c
5
5
  SHA512:
6
- metadata.gz: 52e1eabb4edbadae0d7998946024b8f82b5bd0d3feb2f079cc96643c7dc4774aec3eed6f00563c8b689fc07546a9b1443605fca0f573e2f23fe42b3ff128fd7d
7
- data.tar.gz: 46b81356c5bcbb4931f76f676e2416fddfcc1d396624fff35f61d117dfcb77d3ec63c16878253bc4a0810526adfd2267d93a43466217901fa21886112710845d
6
+ metadata.gz: 2658a0f4e151ab9fd0a56d1096e8d6b191b5e5164e27eadb8dc922651664440149fd1eef7b9d410fbcdf781eba3ef046b141c017b3b5d317b241ec7afa2d8150
7
+ data.tar.gz: 73695493c9f72619279a5552bdea275f6aa781da3da1dadebb788eaff249f68e088b3eb9fc5cc7c3afab1d6df0b44bd83e18ce2aa3605ace83a00035dfd84890
@@ -1,6 +1,12 @@
1
1
  name: Ruby
2
2
 
3
- on: [push,pull_request]
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
4
10
 
5
11
  jobs:
6
12
  tests:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.1.6] - 2024-03-26
4
+
5
+ - Fixed: Channel#wait_for_confirms now waits for all confirms, in a thread safe way
6
+ - Changed: When server sends Connection.blocked the client isn't write blocked anymore, and can continue consume for instance. However, the on_blocked/unblocked callbacks should be used and manually stop publishing as the server otherwise will stop reading from the client socket.
7
+
3
8
  ## [1.1.5] - 2024-03-15
4
9
 
5
10
  - Fixed: Correctly reference the `UnexpectedFrameEnd` exception
data/Gemfile CHANGED
@@ -11,6 +11,8 @@ gem "minitest", "~> 5.0"
11
11
 
12
12
  gem "rubocop", "~> 1.7"
13
13
 
14
+ gem "rubocop-minitest", require: false
15
+
14
16
  gem "yard", require: false
15
17
 
16
- gem "rubocop-minitest", require: false
18
+ gem "redcarpet", require: false, platforms: :ruby
data/README.md CHANGED
@@ -123,7 +123,7 @@ Or install it yourself as:
123
123
 
124
124
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
125
125
 
126
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the changelog and version number in `version.rb`, make a commit, and then run `bundle exec rake release:source_control_push`, which will create a git tag for the version, push git commits and the created tag. GitHub Actions will then push the `.gem` file to [rubygems.org](https://rubygems.org).
126
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the changelog and version number in `version.rb`, make a commit, and then run `bundle exec rake release:source_control_push`, which will create a git tag for the version, push git commits and the created tag. GitHub Actions will then push the `.gem` file to [rubygems.org](https://rubygems.org/gems/amqp-client).
127
127
 
128
128
  ## Contributing
129
129
 
data/Rakefile CHANGED
@@ -22,4 +22,8 @@ RuboCop::RakeTask.new do |task|
22
22
  task.requires << "rubocop-minitest"
23
23
  end
24
24
 
25
+ require "yard"
26
+
27
+ YARD::Rake::YardocTask.new
28
+
25
29
  task default: [:test, *(:rubocop if RUBY_ENGINE == "ruby")]
@@ -22,8 +22,9 @@ module AMQP
22
22
  @open = false
23
23
  @on_return = nil
24
24
  @confirm = nil
25
- @unconfirmed = ::Queue.new
26
- @unconfirmed_empty = ::Queue.new
25
+ @unconfirmed = []
26
+ @unconfirmed_lock = Mutex.new
27
+ @unconfirmed_empty = ConditionVariable.new
27
28
  @basic_gets = ::Queue.new
28
29
  end
29
30
 
@@ -60,7 +61,7 @@ module AMQP
60
61
  expect :channel_close_ok
61
62
  @replies.close
62
63
  @basic_gets.close
63
- @unconfirmed_empty.close
64
+ @unconfirmed_lock.synchronize { @unconfirmed_empty.broadcast }
64
65
  @consumers.each_value(&:close)
65
66
  nil
66
67
  end
@@ -73,7 +74,7 @@ module AMQP
73
74
  @closed = [level, code, reason, classid, methodid]
74
75
  @replies.close
75
76
  @basic_gets.close
76
- @unconfirmed_empty.close
77
+ @unconfirmed_lock.synchronize { @unconfirmed_empty.broadcast }
77
78
  @consumers.each_value(&:close)
78
79
  @consumers.each_value(&:clear) # empty the queues too, messages can't be acked anymore
79
80
  nil
@@ -267,12 +268,15 @@ module AMQP
267
268
  when true then properties[:delivery_mode] = 2
268
269
  when false then properties[:delivery_mode] = 1
269
270
  end
270
-
271
+ if @confirm
272
+ @unconfirmed_lock.synchronize do
273
+ @unconfirmed.push @confirm += 1
274
+ end
275
+ end
271
276
  if body.bytesize.between?(1, body_max)
272
277
  write_bytes FrameBytes.basic_publish(id, exchange, routing_key, mandatory),
273
278
  FrameBytes.header(id, body.bytesize, properties),
274
279
  FrameBytes.body(id, body)
275
- @unconfirmed.push @confirm += 1 if @confirm
276
280
  return
277
281
  end
278
282
 
@@ -285,7 +289,6 @@ module AMQP
285
289
  write_bytes FrameBytes.body(id, body_part)
286
290
  pos += len
287
291
  end
288
- @unconfirmed.push @confirm += 1 if @confirm
289
292
  nil
290
293
  end
291
294
 
@@ -396,42 +399,44 @@ module AMQP
396
399
  # @param no_wait [Boolean] If false the method will block until the broker has confirmed the request
397
400
  # @return [nil]
398
401
  def confirm_select(no_wait: false)
399
- return if @confirm
402
+ return if @confirm # fast path
400
403
 
401
- write_bytes FrameBytes.confirm_select(@id, no_wait)
402
- expect :confirm_select_ok unless no_wait
403
- @confirm = 0
404
+ @unconfirmed_lock.synchronize do
405
+ # check again in case another thread already did this while we waited for the lock
406
+ return if @confirm
407
+
408
+ write_bytes FrameBytes.confirm_select(@id, no_wait)
409
+ expect :confirm_select_ok unless no_wait
410
+ @confirm = 0
411
+ end
404
412
  nil
405
413
  end
406
414
 
407
415
  # Block until all publishes messages are confirmed
408
- # @return [Boolean] True if all message where positivly acknowledged, false if not
416
+ # @return nil
409
417
  def wait_for_confirms
410
- return true if @unconfirmed.empty?
411
-
412
- ok = @unconfirmed_empty.pop
413
- raise Error::Closed.new(@id, *@closed) if ok.nil?
414
-
415
- ok
418
+ @unconfirmed_lock.synchronize do
419
+ until @unconfirmed.empty?
420
+ @unconfirmed_empty.wait(@unconfirmed_lock)
421
+ raise Error::Closed.new(@id, *@closed) if @closed
422
+ end
423
+ end
416
424
  end
417
425
 
418
426
  # Called by Connection when received ack/nack from broker
419
427
  # @api private
420
428
  def confirm(args)
421
- ack_or_nack, delivery_tag, multiple = *args
422
- loop do
423
- tag = @unconfirmed.pop(true)
424
- break if tag == delivery_tag
425
- next if multiple && tag < delivery_tag
426
-
427
- @unconfirmed << tag # requeue
428
- rescue ThreadError
429
- break
429
+ _ack_or_nack, delivery_tag, multiple = *args
430
+ @unconfirmed_lock.synchronize do
431
+ case multiple
432
+ when true
433
+ idx = @unconfirmed.index(delivery_tag) || raise("Delivery tag not found")
434
+ @unconfirmed.shift(idx + 1)
435
+ when false
436
+ @unconfirmed.delete(delivery_tag) || raise("Delivery tag not found")
437
+ end
438
+ @unconfirmed_empty.broadcast if @unconfirmed.empty?
430
439
  end
431
- return unless @unconfirmed.empty?
432
-
433
- ok = ack_or_nack == :ack
434
- @unconfirmed_empty.push(ok) until @unconfirmed_empty.num_waiting.zero?
435
440
  end
436
441
 
437
442
  # @!endgroup
@@ -54,6 +54,16 @@ module AMQP
54
54
  Thread.new { read_loop } if read_loop_thread
55
55
  end
56
56
 
57
+ # Indicates that the server is blocking publishes.
58
+ # If the client keeps publishing the server will stop reading from the socket.
59
+ # Use the #on_blocked callback to get notified when the server is resource constrained.
60
+ # @see #on_blocked
61
+ # @see #on_unblocked
62
+ # @return [Bool]
63
+ def blocked?
64
+ !@blocked.nil?
65
+ end
66
+
57
67
  # Alias for {#initialize}
58
68
  # @see #initialize
59
69
  # @deprecated
@@ -241,10 +251,8 @@ module AMQP
241
251
  reason_len = buf.getbyte(4)
242
252
  reason = buf.byteslice(5, reason_len).force_encoding("utf-8")
243
253
  @blocked = reason
244
- @write_lock.lock
245
254
  @on_blocked.call(reason)
246
255
  when 61 # connection#unblocked
247
- @write_lock.unlock
248
256
  @blocked = nil
249
257
  @on_unblocked.call
250
258
  else raise Error::UnsupportedMethodFrame, class_id, method_id
@@ -3,6 +3,6 @@
3
3
  module AMQP
4
4
  class Client
5
5
  # Version of the client library
6
- VERSION = "1.1.5"
6
+ VERSION = "1.1.6"
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amqp-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.5
4
+ version: 1.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carl Hörberg
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-15 00:00:00.000000000 Z
11
+ date: 2024-03-26 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Modern AMQP 0-9-1 Ruby client
14
14
  email: