amqp-client 1.1.4 → 1.1.5

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: 0e287ef0dee4c9ec581690733c12c132f74c595ceddead1ba5b95b765138e11c
4
- data.tar.gz: e5462c8cd2a4f7232a51e17d9ec93f4fb2ea88a922bb9b5cc58242cced78d61e
3
+ metadata.gz: d3a9c50ecceb8a9d86bfea50d67957c1b063c47d35d85291b29e79b2631de262
4
+ data.tar.gz: 055da4bc7ab51bac9f6839bf225c4f737b8aa766320609031ed68fa6b709cb88
5
5
  SHA512:
6
- metadata.gz: 923fb64c7234fb6718f7dbc5eb33c1f8de03a9cf12d669539935cc6ef83f4ca387afc80c1e56fcc2ed167dc14381cda1d7b6a67673c6516818909cb6a84c287d
7
- data.tar.gz: 14c4d9157cee844609eeb5beed70ee2560ba3442c5afb857fed3e0945c443910f7bd4a281e327d2cb5ee0f0896facf4c8e693e5d3ecf1152c07474e20f8a724f
6
+ metadata.gz: 52e1eabb4edbadae0d7998946024b8f82b5bd0d3feb2f079cc96643c7dc4774aec3eed6f00563c8b689fc07546a9b1443605fca0f573e2f23fe42b3ff128fd7d
7
+ data.tar.gz: 46b81356c5bcbb4931f76f676e2416fddfcc1d396624fff35f61d117dfcb77d3ec63c16878253bc4a0810526adfd2267d93a43466217901fa21886112710845d
@@ -0,0 +1,41 @@
1
+ name: "CodeQL"
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ # The branches below must be a subset of the branches above
8
+ branches: [ main ]
9
+ schedule:
10
+ - cron: '23 22 * * 2'
11
+
12
+ jobs:
13
+ analyze:
14
+ name: Analyze
15
+ runs-on: ubuntu-latest
16
+ permissions:
17
+ actions: read
18
+ contents: read
19
+ security-events: write
20
+
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ language: [ 'ruby' ]
25
+
26
+ steps:
27
+ - name: Checkout repository
28
+ uses: actions/checkout@v4
29
+
30
+ # Initializes the CodeQL tools for scanning.
31
+ - name: Initialize CodeQL
32
+ uses: github/codeql-action/init@v3
33
+ with:
34
+ languages: ${{ matrix.language }}
35
+ # If you wish to specify custom queries, you can do so here or in a config file.
36
+ # By default, queries listed here will override any specified in a config file.
37
+ # Prefix the list here with "+" to use these queries and those in the config file.
38
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
39
+
40
+ - name: Perform CodeQL Analysis
41
+ uses: github/codeql-action/analyze@v3
@@ -12,17 +12,17 @@ jobs:
12
12
  docs:
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/checkout@v2
15
+ - uses: actions/checkout@v4
16
16
  - name: Setup Ruby
17
17
  uses: ruby/setup-ruby@v1
18
18
  with:
19
- ruby-version: 3.0
19
+ ruby-version: ruby
20
20
  - name: Install yard
21
21
  run: gem install yard
22
22
  - name: Generate docs
23
23
  run: yard doc
24
24
  - name: Deploy docs
25
- uses: JamesIves/github-pages-deploy-action@4.1.5
25
+ uses: JamesIves/github-pages-deploy-action@v4.5.0
26
26
  with:
27
27
  branch: gh-pages
28
28
  folder: doc
@@ -4,30 +4,31 @@ on: [push,pull_request]
4
4
 
5
5
  jobs:
6
6
  tests:
7
+ name: >-
8
+ ${{ matrix.ruby }} (sudo: ${{ matrix.sudo }})
7
9
  runs-on: ubuntu-latest
8
- timeout-minutes: 5
9
- services:
10
- rabbitmq:
11
- image: rabbitmq:latest
12
- ports:
13
- - 5672/tcp
14
- # needed because the rabbitmq container does not provide a healthcheck
15
- options: >-
16
- --health-cmd "rabbitmqctl node_health_check"
17
- --health-interval 10s
18
- --health-timeout 5s
19
- --health-retries 5
10
+ timeout-minutes: 10
20
11
  strategy:
21
12
  fail-fast: false
22
13
  matrix:
23
- ruby: ['2.6', '2.7', '3.0', '3.1']
14
+ sudo: [true]
15
+ ruby:
16
+ - "2.6"
17
+ - "2.7"
18
+ - "3.0"
19
+ - "3.1"
20
+ - "3.2"
21
+ - "3.3"
24
22
  include:
25
- - { ruby: jruby, allow-failure: true }
26
- - { ruby: truffleruby, allow-failure: true }
23
+ - { ruby: jruby, allow-failure: true, sudo: false }
24
+ - { ruby: truffleruby, allow-failure: true, sudo: false }
27
25
  steps:
28
- - uses: actions/checkout@v2
29
- - name: Set up Ruby
30
- uses: ruby/setup-ruby@v1
26
+ - name: Install RabbitMQ
27
+ run: sudo apt-get update && sudo apt-get install -y rabbitmq-server
28
+ - name: Verify RabbitMQ started correctly
29
+ run: while true; do sudo rabbitmq-diagnostics status 2>/dev/null && break; echo -n .; sleep 2; done
30
+ - uses: actions/checkout@v4
31
+ - uses: ruby/setup-ruby@v1
31
32
  with:
32
33
  bundler-cache: true
33
34
  ruby-version: ${{ matrix.ruby }}
@@ -35,20 +36,25 @@ jobs:
35
36
  continue-on-error: ${{ matrix.allow-failure || false }}
36
37
  run: bundle exec rake
37
38
  env:
38
- AMQP_PORT: ${{ job.services.rabbitmq.ports[5672] }}
39
+ RUN_SUDO_TESTS: ${{ matrix.sudo }}
40
+
39
41
  tls:
40
42
  runs-on: ubuntu-latest
41
- timeout-minutes: 5
43
+ timeout-minutes: 10
42
44
  strategy:
43
45
  fail-fast: false
44
46
  matrix:
45
- ruby: ['3.0', 'jruby', 'truffleruby']
47
+ ruby:
48
+ - "ruby" # latest stable release
49
+ - "jruby"
50
+ - "truffleruby"
46
51
  steps:
47
52
  - name: Install RabbitMQ
48
53
  run: sudo apt-get update && sudo apt-get install -y rabbitmq-server
49
54
  - name: Stop RabbitMQ
50
55
  run: sudo systemctl stop rabbitmq-server
51
-
56
+ - name: Set up Homebrew
57
+ uses: Homebrew/actions/setup-homebrew@master
52
58
  - name: Install github.com/FiloSottile/mkcert
53
59
  run: brew install mkcert
54
60
  - name: Create local CA
@@ -69,10 +75,8 @@ jobs:
69
75
  run: sudo systemctl start rabbitmq-server
70
76
  - name: Verify RabbitMQ started correctly
71
77
  run: while true; do sudo rabbitmq-diagnostics status 2>/dev/null && break; echo -n .; sleep 2; done
72
-
73
- - uses: actions/checkout@v2
74
- - name: Set up Ruby
75
- uses: ruby/setup-ruby@v1
78
+ - uses: actions/checkout@v4
79
+ - uses: ruby/setup-ruby@v1
76
80
  with:
77
81
  bundler-cache: true
78
82
  ruby-version: ${{ matrix.ruby }}
@@ -80,21 +84,22 @@ jobs:
80
84
  run: bundle exec rake
81
85
  env:
82
86
  TESTOPTS: --name=/_tls$/
87
+
83
88
  macos:
84
89
  runs-on: macos-latest
85
- timeout-minutes: 5
90
+ timeout-minutes: 10
86
91
  strategy:
87
92
  fail-fast: false
88
93
  matrix:
89
- ruby: ['3.0']
94
+ ruby: # enough to test one Ruby on macOS
95
+ - "ruby" # latest stable release
90
96
  steps:
91
97
  - name: Install RabbitMQ
92
98
  run: brew install rabbitmq
93
99
  - name: Start RabbitMQ
94
100
  run: brew services start rabbitmq
95
- - uses: actions/checkout@v2
96
- - name: Set up Ruby
97
- uses: ruby/setup-ruby@v1
101
+ - uses: actions/checkout@v4
102
+ - uses: ruby/setup-ruby@v1
98
103
  with:
99
104
  bundler-cache: true
100
105
  ruby-version: ${{ matrix.ruby }}
@@ -0,0 +1,26 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - v*
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ release:
11
+ if: github.repository == 'cloudamqp/amqp-client.rb'
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ id-token: write # for trusted publishing
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: ruby/setup-ruby@v1
18
+ with:
19
+ bundler-cache: true
20
+ ruby-version: ruby
21
+ - uses: rubygems/configure-rubygems-credentials@v1.0.0
22
+ - run: ruby -v
23
+ # ensure gem can be built and installed, push to rubygems.org
24
+ - run: gem build *.gemspec
25
+ - run: gem install *.gem
26
+ - run: gem push *.gem
data/.rubocop.yml CHANGED
@@ -1,7 +1,9 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
3
  AllCops:
4
+ NewCops: disable
4
5
  TargetRubyVersion: 2.6
6
+ SuggestExtensions: false
5
7
 
6
8
  Style/StringLiterals:
7
9
  Enabled: true
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.1.5] - 2024-03-15
4
+
5
+ - Fixed: Correctly reference the `UnexpectedFrameEnd` exception
6
+
3
7
  ## [1.1.4] - 2021-12-27
4
8
 
5
9
  - Fixed: Ruby 3.1.0 compability, StringIO have to be required manually
data/README.md CHANGED
@@ -49,6 +49,10 @@ puts msg.body
49
49
  The library provides a high-level API that is a bit easier to get started with, and also handles reconnection automatically.
50
50
 
51
51
  ```ruby
52
+ require "amqp-client"
53
+ require "json"
54
+ require "zlib"
55
+
52
56
  # Start the client, it will connect and once connected it will reconnect if that connection is lost
53
57
  # Operation pending when the connection is lost will raise an exception (not timeout)
54
58
  amqp = AMQP::Client.new("amqp://localhost").start
@@ -62,9 +66,10 @@ myqueue.bind("amq.topic", "my.events.*")
62
66
  # The message will be reprocessed if the client loses connection to the broker
63
67
  # between message arrival and when the message was supposed to be ack'ed.
64
68
  myqueue.subscribe(prefetch: 20) do |msg|
65
- process(JSON.parse(msg.body))
69
+ puts JSON.parse(msg.body)
66
70
  msg.ack
67
- rescue
71
+ rescue => e
72
+ puts e.full_message
68
73
  msg.reject(requeue: false)
69
74
  end
70
75
 
@@ -76,16 +81,27 @@ amqp.publish("my message", "amq.topic", "topic.foo", headers: { foo: 'bar' })
76
81
  amqp.publish(Zlib.gzip("an event"), "amq.topic", "my.event", content_encoding: 'gzip')
77
82
  ```
78
83
 
84
+ ## Benchmark
85
+
86
+ 1 byte messages:
87
+
88
+ | Client | Publish rate | Consume rate | Memory usage |
89
+ | ------ | ------------ | ------------ | ------------ |
90
+ | amqp-client.rb | 237.000 msgs/s | 154.000 msgs/s | 23 MB |
91
+ | bunny | 39.000 msgs/s | 44.000 msgs/s | 31 MB |
92
+
93
+ Gem comparison:
94
+
95
+ | Client | Runtime dependencies | [Lines of code](https://github.com/AlDanial/cloc) |
96
+ | --- | --- | --- |
97
+ | amqp-client.rb | 0 | 1876 |
98
+ | bunny | 2 | 4003 |
99
+
79
100
  ## Supported Ruby versions
80
101
 
81
102
  All maintained Ruby versions are supported.
82
103
 
83
- - 3.1
84
- - 3.0
85
- - 2.7
86
- - 2.6
87
- - jruby
88
- - truffleruby
104
+ See the [CI workflow](https://github.com/cloudamqp/amqp-client.rb/blob/main/.github/workflows/main.yml) for the exact versions.
89
105
 
90
106
  ## Installation
91
107
 
@@ -107,7 +123,7 @@ Or install it yourself as:
107
123
 
108
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.
109
125
 
110
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and 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).
111
127
 
112
128
  ## Contributing
113
129
 
data/amqp-client.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ["carl@cloudamqp.com"]
10
10
 
11
11
  spec.summary = "AMQP 0-9-1 client"
12
- spec.description = "Work in progress"
12
+ spec.description = "Modern AMQP 0-9-1 Ruby client"
13
13
  spec.homepage = "https://github.com/cloudamqp/amqp-client.rb"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
@@ -26,10 +26,4 @@ Gem::Specification.new do |spec|
26
26
  spec.bindir = "exe"
27
27
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
-
30
- # Uncomment to register a new dependency of your gem
31
- # spec.add_dependency "example-gem", "~> 1.0"
32
-
33
- # For more information and examples about making a new gem, checkout our
34
- # guide at: https://bundler.io/guides/creating_gem.html
35
29
  end
@@ -75,6 +75,7 @@ module AMQP
75
75
  @basic_gets.close
76
76
  @unconfirmed_empty.close
77
77
  @consumers.each_value(&:close)
78
+ @consumers.each_value(&:clear) # empty the queues too, messages can't be acked anymore
78
79
  nil
79
80
  end
80
81
 
@@ -200,11 +201,12 @@ module AMQP
200
201
  # Purge a queue
201
202
  # @param name [String] Name of the queue
202
203
  # @param no_wait [Boolean] Don't wait for a broker confirmation if true
203
- # @return [nil]
204
+ # @return [Integer] Number of messages in queue when purged
205
+ # @return [nil] If no_wait was set true
204
206
  def queue_purge(name, no_wait: false)
205
207
  write_bytes FrameBytes.queue_purge(@id, name, no_wait)
206
- expect :queue_purge_ok unless no_wait
207
- nil
208
+ message_count, = expect :queue_purge_ok unless no_wait
209
+ message_count
208
210
  end
209
211
 
210
212
  # Unbind a queue from an exchange
@@ -310,22 +312,16 @@ module AMQP
310
312
  # @yield [Message] Delivered message from the queue
311
313
  # @return [Array<(String, Array<Thread>)>] Returns consumer_tag and an array of worker threads
312
314
  # @return [nil] When `worker_threads` is 0 the method will return when the consumer is cancelled
313
- def basic_consume(queue, tag: "", no_ack: true, exclusive: false, arguments: {}, worker_threads: 1)
315
+ def basic_consume(queue, tag: "", no_ack: true, exclusive: false, arguments: {}, worker_threads: 1, &blk)
314
316
  write_bytes FrameBytes.basic_consume(@id, queue, tag, no_ack, exclusive, arguments)
315
317
  tag, = expect(:basic_consume_ok)
316
- q = @consumers[tag] = ::Queue.new
318
+ @consumers[tag] = q = ::Queue.new
317
319
  if worker_threads.zero?
318
- loop do
319
- yield (q.pop || break)
320
- end
320
+ consume_loop(q, tag, &blk)
321
321
  nil
322
322
  else
323
323
  threads = Array.new(worker_threads) do
324
- Thread.new do
325
- loop do
326
- yield (q.pop || break)
327
- end
328
- end
324
+ Thread.new { consume_loop(q, tag, &blk) }
329
325
  end
330
326
  [tag, threads]
331
327
  end
@@ -547,6 +543,21 @@ module AMQP
547
543
 
548
544
  args
549
545
  end
546
+
547
+ def consume_loop(queue, tag)
548
+ while (msg = queue.pop)
549
+ begin
550
+ yield msg
551
+ rescue StandardError # cancel the consumer if an uncaught exception is raised
552
+ begin
553
+ close("Unexpected exception in consumer #{tag} thread", 500)
554
+ rescue StandardError # ignore sockets errors while canceling
555
+ nil
556
+ end
557
+ raise # reraise original exception
558
+ end
559
+ end
560
+ end
550
561
  end
551
562
  end
552
563
  end
@@ -48,6 +48,9 @@ module AMQP
48
48
  @replies = ::Queue.new
49
49
  @write_lock = Mutex.new
50
50
  @blocked = nil
51
+ @on_blocked = ->(reason) { warn "AMQP-Client blocked by broker: #{reason}" }
52
+ @on_unblocked = -> { warn "AMQP-Client unblocked by broker" }
53
+
51
54
  Thread.new { read_loop } if read_loop_thread
52
55
  end
53
56
 
@@ -125,20 +128,33 @@ module AMQP
125
128
  !@closed.nil?
126
129
  end
127
130
 
131
+ # @!group Callbacks
132
+
133
+ # Callback called when client is blocked by the broker
134
+ # @yield [String] reason to why the connection is being blocked
135
+ # @return [nil]
136
+ def on_blocked(&blk)
137
+ @on_blocked = blk
138
+ nil
139
+ end
140
+
141
+ # Callback called when client is unblocked by the broker
142
+ # @yield
143
+ # @return [nil]
144
+ def on_unblocked(&blk)
145
+ @on_unblocked = blk
146
+ nil
147
+ end
148
+
149
+ # @!endgroup
150
+
128
151
  # Write byte array(s) directly to the socket (thread-safe)
129
152
  # @param bytes [String] One or more byte arrays
130
153
  # @return [Integer] number of bytes written
131
154
  # @api private
132
155
  def write_bytes(*bytes)
133
- blocked = @blocked
134
- warn "AMQP-Client blocked by broker: #{blocked}" if blocked
135
156
  @write_lock.synchronize do
136
- warn "AMQP-Client unblocked by broker" if blocked
137
- if RUBY_ENGINE == "truffleruby"
138
- bytes.each { |b| @socket.write b }
139
- else
140
- @socket.write(*bytes)
141
- end
157
+ @socket.write(*bytes)
142
158
  end
143
159
  rescue *READ_EXCEPTIONS => e
144
160
  raise Error::ConnectionClosed.new(*@closed) if @closed
@@ -166,7 +182,7 @@ module AMQP
166
182
 
167
183
  # make sure that the frame end is correct
168
184
  frame_end = socket.readchar.ord
169
- raise UnexpectedFrameEnd, frame_end if frame_end != 206
185
+ raise Error::UnexpectedFrameEnd, frame_end if frame_end != 206
170
186
 
171
187
  # parse the frame, will return false if a close frame was received
172
188
  parse_frame(type, channel_id, frame_buffer) || return
@@ -179,8 +195,12 @@ module AMQP
179
195
  @closed ||= [400, "unknown"]
180
196
  @replies.close
181
197
  begin
182
- @write_lock.synchronize do
198
+ if @write_lock.owned? # if connection is blocked
183
199
  @socket.close
200
+ else
201
+ @write_lock.synchronize do
202
+ @socket.close
203
+ end
184
204
  end
185
205
  rescue *READ_EXCEPTIONS
186
206
  nil
@@ -192,7 +212,8 @@ module AMQP
192
212
  READ_EXCEPTIONS = [IOError, OpenSSL::OpenSSLError, SystemCallError,
193
213
  RUBY_ENGINE == "jruby" ? java.lang.NullPointerException : nil].compact.freeze
194
214
 
195
- def parse_frame(type, channel_id, buf)
215
+ def parse_frame(type, channel_id, buf) # rubocop:disable Metrics/MethodLength
216
+ channel = @channels[channel_id]
196
217
  case type
197
218
  when 1 # method frame
198
219
  class_id, method_id = buf.unpack("S> S>")
@@ -221,15 +242,17 @@ module AMQP
221
242
  reason = buf.byteslice(5, reason_len).force_encoding("utf-8")
222
243
  @blocked = reason
223
244
  @write_lock.lock
245
+ @on_blocked.call(reason)
224
246
  when 61 # connection#unblocked
225
- @blocked = nil
226
247
  @write_lock.unlock
248
+ @blocked = nil
249
+ @on_unblocked.call
227
250
  else raise Error::UnsupportedMethodFrame, class_id, method_id
228
251
  end
229
252
  when 20 # channel
230
253
  case method_id
231
254
  when 11 # channel#open-ok
232
- @channels[channel_id].reply [:channel_open_ok]
255
+ channel.reply [:channel_open_ok]
233
256
  when 40 # channel#close
234
257
  reply_code, reply_text_len = buf.unpack("@4 S> C")
235
258
  reply_text = buf.byteslice(7, reply_text_len).force_encoding("utf-8")
@@ -245,13 +268,13 @@ module AMQP
245
268
  when 40 # exchange
246
269
  case method_id
247
270
  when 11 # declare-ok
248
- @channels[channel_id].reply [:exchange_declare_ok]
271
+ channel.reply [:exchange_declare_ok]
249
272
  when 21 # delete-ok
250
- @channels[channel_id].reply [:exchange_delete_ok]
273
+ channel.reply [:exchange_delete_ok]
251
274
  when 31 # bind-ok
252
- @channels[channel_id].reply [:exchange_bind_ok]
275
+ channel.reply [:exchange_bind_ok]
253
276
  when 51 # unbind-ok
254
- @channels[channel_id].reply [:exchange_unbind_ok]
277
+ channel.reply [:exchange_unbind_ok]
255
278
  else raise Error::UnsupportedMethodFrame, class_id, method_id
256
279
  end
257
280
  when 50 # queue
@@ -260,36 +283,37 @@ module AMQP
260
283
  queue_name_len = buf.getbyte(4)
261
284
  queue_name = buf.byteslice(5, queue_name_len).force_encoding("utf-8")
262
285
  message_count, consumer_count = buf.byteslice(5 + queue_name_len, 8).unpack("L> L>")
263
- @channels[channel_id].reply [:queue_declare_ok, queue_name, message_count, consumer_count]
286
+ channel.reply [:queue_declare_ok, queue_name, message_count, consumer_count]
264
287
  when 21 # bind-ok
265
- @channels[channel_id].reply [:queue_bind_ok]
288
+ channel.reply [:queue_bind_ok]
266
289
  when 31 # purge-ok
267
- @channels[channel_id].reply [:queue_purge_ok]
290
+ message_count = buf.unpack1("@4 L>")
291
+ channel.reply [:queue_purge_ok, message_count]
268
292
  when 41 # delete-ok
269
293
  message_count = buf.unpack1("@4 L>")
270
- @channels[channel_id].reply [:queue_delete, message_count]
294
+ channel.reply [:queue_delete, message_count]
271
295
  when 51 # unbind-ok
272
- @channels[channel_id].reply [:queue_unbind_ok]
296
+ channel.reply [:queue_unbind_ok]
273
297
  else raise Error::UnsupportedMethodFrame.new class_id, method_id
274
298
  end
275
299
  when 60 # basic
276
300
  case method_id
277
301
  when 11 # qos-ok
278
- @channels[channel_id].reply [:basic_qos_ok]
302
+ channel.reply [:basic_qos_ok]
279
303
  when 21 # consume-ok
280
304
  tag_len = buf.getbyte(4)
281
305
  tag = buf.byteslice(5, tag_len).force_encoding("utf-8")
282
- @channels[channel_id].reply [:basic_consume_ok, tag]
306
+ channel.reply [:basic_consume_ok, tag]
283
307
  when 30 # cancel
284
308
  tag_len = buf.getbyte(4)
285
309
  tag = buf.byteslice(5, tag_len).force_encoding("utf-8")
286
310
  no_wait = buf.getbyte(5 + tag_len) == 1
287
- @channels[channel_id].close_consumer(tag)
311
+ channel.close_consumer(tag)
288
312
  write_bytes FrameBytes.basic_cancel_ok(@id, tag) unless no_wait
289
313
  when 31 # cancel-ok
290
314
  tag_len = buf.getbyte(4)
291
315
  tag = buf.byteslice(5, tag_len).force_encoding("utf-8")
292
- @channels[channel_id].reply [:basic_cancel_ok, tag]
316
+ channel.reply [:basic_cancel_ok, tag]
293
317
  when 50 # return
294
318
  reply_code, reply_text_len = buf.unpack("@4 S> C")
295
319
  pos = 7
@@ -302,7 +326,7 @@ module AMQP
302
326
  routing_key_len = buf.getbyte(pos)
303
327
  pos += 1
304
328
  routing_key = buf.byteslice(pos, routing_key_len).force_encoding("utf-8")
305
- @channels[channel_id].message_returned(reply_code, reply_text, exchange, routing_key)
329
+ channel.message_returned(reply_code, reply_text, exchange, routing_key)
306
330
  when 60 # deliver
307
331
  ctag_len = buf.getbyte(4)
308
332
  consumer_tag = buf.byteslice(5, ctag_len).force_encoding("utf-8")
@@ -314,7 +338,7 @@ module AMQP
314
338
  rk_len = buf.getbyte(pos)
315
339
  pos += 1
316
340
  routing_key = buf.byteslice(pos, rk_len).force_encoding("utf-8")
317
- @channels[channel_id].message_delivered(consumer_tag, delivery_tag, redelivered == 1, exchange, routing_key)
341
+ channel.message_delivered(consumer_tag, delivery_tag, redelivered == 1, exchange, routing_key)
318
342
  when 71 # get-ok
319
343
  delivery_tag, redelivered, exchange_len = buf.unpack("@4 Q> C C")
320
344
  pos = 14
@@ -325,33 +349,33 @@ module AMQP
325
349
  routing_key = buf.byteslice(pos, routing_key_len).force_encoding("utf-8")
326
350
  # pos += routing_key_len
327
351
  # message_count = buf.byteslice(pos, 4).unpack1("L>")
328
- @channels[channel_id].message_delivered(nil, delivery_tag, redelivered == 1, exchange, routing_key)
352
+ channel.message_delivered(nil, delivery_tag, redelivered == 1, exchange, routing_key)
329
353
  when 72 # get-empty
330
- @channels[channel_id].basic_get_empty
354
+ channel.basic_get_empty
331
355
  when 80 # ack
332
356
  delivery_tag, multiple = buf.unpack("@4 Q> C")
333
- @channels[channel_id].confirm [:ack, delivery_tag, multiple == 1]
357
+ channel.confirm [:ack, delivery_tag, multiple == 1]
334
358
  when 111 # recover-ok
335
- @channels[channel_id].reply [:basic_recover_ok]
359
+ channel.reply [:basic_recover_ok]
336
360
  when 120 # nack
337
361
  delivery_tag, multiple, requeue = buf.unpack("@4 Q> C C")
338
- @channels[channel_id].confirm [:nack, delivery_tag, multiple == 1, requeue == 1]
362
+ channel.confirm [:nack, delivery_tag, multiple == 1, requeue == 1]
339
363
  else raise Error::UnsupportedMethodFrame.new class_id, method_id
340
364
  end
341
365
  when 85 # confirm
342
366
  case method_id
343
367
  when 11 # select-ok
344
- @channels[channel_id].reply [:confirm_select_ok]
368
+ channel.reply [:confirm_select_ok]
345
369
  else raise Error::UnsupportedMethodFrame.new class_id, method_id
346
370
  end
347
371
  when 90 # tx
348
372
  case method_id
349
373
  when 11 # select-ok
350
- @channels[channel_id].reply [:tx_select_ok]
374
+ channel.reply [:tx_select_ok]
351
375
  when 21 # commit-ok
352
- @channels[channel_id].reply [:tx_commit_ok]
376
+ channel.reply [:tx_commit_ok]
353
377
  when 31 # rollback-ok
354
- @channels[channel_id].reply [:tx_rollback_ok]
378
+ channel.reply [:tx_rollback_ok]
355
379
  else raise Error::UnsupportedMethodFrame.new class_id, method_id
356
380
  end
357
381
  else raise Error::UnsupportedMethodFrame.new class_id, method_id
@@ -359,9 +383,9 @@ module AMQP
359
383
  when 2 # header
360
384
  body_size = buf.unpack1("@4 Q>")
361
385
  properties = Properties.decode(buf, 12)
362
- @channels[channel_id].header_delivered body_size, properties
386
+ channel.header_delivered body_size, properties
363
387
  when 3 # body
364
- @channels[channel_id].body_delivered buf
388
+ channel.body_delivered buf
365
389
  else raise Error::UnsupportedFrameType, type
366
390
  end
367
391
  true
@@ -419,7 +443,7 @@ module AMQP
419
443
 
420
444
  type, channel_id, frame_size = buf.unpack("C S> L>")
421
445
  frame_end = buf.getbyte(frame_size + 7)
422
- raise UnexpectedFrameEndError, frame_end if frame_end != 206
446
+ raise Error::UnexpectedFrameEnd, frame_end if frame_end != 206
423
447
 
424
448
  case type
425
449
  when 1 # method frame
@@ -3,6 +3,6 @@
3
3
  module AMQP
4
4
  class Client
5
5
  # Version of the client library
6
- VERSION = "1.1.4"
6
+ VERSION = "1.1.5"
7
7
  end
8
8
  end
data/lib/amqp/client.rb CHANGED
@@ -26,7 +26,6 @@ module AMQP
26
26
  def initialize(uri = "", **options)
27
27
  @uri = uri
28
28
  @options = options
29
-
30
29
  @queues = {}
31
30
  @exchanges = {}
32
31
  @subscriptions = Set.new
@@ -172,15 +171,16 @@ module AMQP
172
171
 
173
172
  # Consume messages from a queue
174
173
  # @param queue [String] Name of the queue to subscribe to
175
- # @param no_ack [Boolean] When false messages have to be manually acknowledged (or rejected)
176
- # @param prefetch [Integer] Specify how many messages to prefetch for consumers with no_ack is false
177
- # @param worker_threads [Integer] Number of threads processing messages,
178
- # 0 means that the thread calling this method will be blocked
174
+ # @param no_ack [Boolean] When false messages have to be manually acknowledged (or rejected) (default: false)
175
+ # @param prefetch [Integer] Specify how many messages to prefetch for consumers with no_ack is false (default: 1)
176
+ # @param worker_threads [Integer] Number of threads processing messages (default: 1)
179
177
  # @param arguments [Hash] Custom arguments to the consumer
180
178
  # @yield [Message] Delivered message from the queue
181
179
  # @return [Array<(String, Array<Thread>)>] Returns consumer_tag and an array of worker threads
182
- # @return [nil] When `worker_threads` is 0 the method will return when the consumer is cancelled
180
+ # @return [nil]
183
181
  def subscribe(queue, no_ack: false, prefetch: 1, worker_threads: 1, arguments: {}, &blk)
182
+ raise ArgumentError, "worker_threads have to be > 0" if worker_threads <= 0
183
+
184
184
  @subscriptions.add? [queue, no_ack, prefetch, worker_threads, arguments, blk]
185
185
 
186
186
  with_connection do |conn|
metadata CHANGED
@@ -1,24 +1,26 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amqp-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carl Hörberg
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-27 00:00:00.000000000 Z
11
+ date: 2024-03-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Work in progress
13
+ description: Modern AMQP 0-9-1 Ruby client
14
14
  email:
15
15
  - carl@cloudamqp.com
16
16
  executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - ".github/workflows/codeql-analysis.yml"
20
21
  - ".github/workflows/docs.yml"
21
22
  - ".github/workflows/main.yml"
23
+ - ".github/workflows/release.yml"
22
24
  - ".gitignore"
23
25
  - ".rubocop.yml"
24
26
  - ".rubocop_todo.yml"
@@ -43,7 +45,6 @@ files:
43
45
  - lib/amqp/client/queue.rb
44
46
  - lib/amqp/client/table.rb
45
47
  - lib/amqp/client/version.rb
46
- - sig/amqp-client.rbs
47
48
  homepage: https://github.com/cloudamqp/amqp-client.rb
48
49
  licenses:
49
50
  - MIT
@@ -51,7 +52,7 @@ metadata:
51
52
  homepage_uri: https://github.com/cloudamqp/amqp-client.rb
52
53
  source_code_uri: https://github.com/cloudamqp/amqp-client.rb.git
53
54
  changelog_uri: https://github.com/cloudamqp/amqp-client.rb/blob/main/CHANGELOG.md
54
- post_install_message:
55
+ post_install_message:
55
56
  rdoc_options: []
56
57
  require_paths:
57
58
  - lib
@@ -66,8 +67,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
67
  - !ruby/object:Gem::Version
67
68
  version: '0'
68
69
  requirements: []
69
- rubygems_version: 3.3.3
70
- signing_key:
70
+ rubygems_version: 3.5.3
71
+ signing_key:
71
72
  specification_version: 4
72
73
  summary: AMQP 0-9-1 client
73
74
  test_files: []
data/sig/amqp-client.rbs DELETED
@@ -1,264 +0,0 @@
1
- # TypeProf 0.15.3
2
-
3
- # Classes
4
- module AMQP
5
- class Client
6
- VERSION: String
7
- @uri: String
8
- @options: Hash[Symbol, (String | Integer | bool)]
9
- @queues: Hash[String, Queue]
10
- @exchanges: Hash[String, Exchange]
11
- @subscriptions: Set[[String, bool, Integer, Integer, Hash[Symbol, untyped], nil]]
12
- @connq: Thread::SizedQueue
13
- @stopped: bool
14
-
15
- def initialize: (?String uri, **untyped) -> void
16
- def connect: (?read_loop_thread: bool) -> Connection
17
- def start: -> Client
18
- def stop: -> nil
19
- def queue: (String name, ?durable: bool, ?auto_delete: bool, ?arguments: Hash[Symbol | String, (String | Integer | bool)]) -> Queue
20
- def exchange: (String name, String `type`, ?durable: bool, ?auto_delete: bool, ?internal: bool, ?arguments: Hash[Symbol | String, untyped]) -> Exchange
21
- def publish: (String body, String exchange, String routing_key, **untyped) -> bool
22
- def publish_and_forget: (String body, String exchange, String routing_key, **untyped) -> nil
23
- def wait_for_confirms: -> bool
24
- def subscribe: (String queue, ?no_ack: bool, ?prefetch: Integer, ?worker_threads: Integer, ?arguments: Hash[Symbol | String, untyped]) { (Message) -> void } -> [String, Array[Thread]]?
25
- def bind: (String queue, String exchange, String binding_key, ?arguments: Hash[Symbol | String, untyped]) -> nil
26
- def unbind: (String queue, String exchange, String binding_key, ?arguments: Hash[Symbol | String, untyped]) -> nil
27
- def purge: (String queue) -> nil
28
- def delete_queue: (String name, ?if_unused: bool, ?if_empty: bool) -> Integer?
29
- def exchange_bind: (String destination, String source, String binding_key, ?arguments: Hash[Symbol | String, untyped]) -> nil
30
- def exchange_unbind: (String destination, String source, String binding_key, ?arguments: Hash[Symbol | String, untyped]) -> nil
31
- def delete_exchange: (String name) -> nil
32
- def with_connection: { (Connection) -> void } -> void
33
-
34
- module Table
35
- def self.encode: (Hash[Symbol | String, untyped] hash) -> String
36
- def self.decode: (String bytes) -> Hash[String, untyped]
37
- end
38
-
39
- class Properties
40
- attr_accessor content_type(): String?
41
- attr_accessor content_encoding(): String?
42
- attr_accessor headers(): Hash[String | Symbol, untyped]?
43
- attr_accessor delivery_mode(): Integer?
44
- attr_accessor priority(): Integer?
45
- attr_accessor correlation_id(): String?
46
- attr_accessor reply_to(): String?
47
- attr_accessor expiration(): (Integer | String)?
48
- attr_accessor message_id(): String?
49
- attr_accessor timestamp(): Time?
50
- attr_accessor type(): String?
51
- attr_accessor user_id(): String?
52
- attr_accessor app_id(): String?
53
- end
54
-
55
- module FrameBytes
56
- def self.connection_start_ok: (String response, Hash[untyped, untyped] properties) -> String
57
- def self.connection_tune_ok: ((Float | Integer | String)? channel_max, (Float | Integer | String)? frame_max, (Float | Integer | String)? heartbeat) -> String
58
- def self.connection_open: (String vhost) -> String
59
- def self.connection_close: (Integer code, String reason) -> String
60
- def self.connection_close_ok: -> String
61
- def self.channel_open: (Integer id) -> String
62
- def self.channel_close: (Integer id, String reason, Integer code) -> String
63
- def self.channel_close_ok: ((Float | Integer | String)? id) -> String
64
- def self.exchange_declare: (Integer id, untyped name, untyped `type`, bool passive, bool durable, bool auto_delete, bool internal, Hash[untyped, untyped] arguments) -> String
65
- def self.exchange_delete: (Integer id, untyped name, bool if_unused, bool no_wait) -> String
66
- def self.exchange_bind: (Integer id, untyped destination, untyped source, untyped binding_key, bool no_wait, Hash[untyped, untyped] arguments) -> String
67
- def self.exchange_unbind: (Integer id, untyped destination, untyped source, untyped binding_key, bool no_wait, Hash[untyped, untyped] arguments) -> String
68
- def self.queue_declare: (Integer id, String name, bool passive, bool durable, bool exclusive, bool auto_delete, Hash[untyped, untyped] arguments) -> String
69
- def self.queue_delete: (Integer id, untyped name, bool if_unused, bool if_empty, bool no_wait) -> String
70
- def self.queue_bind: (Integer id, untyped queue, untyped exchange, untyped binding_key, bool no_wait, Hash[untyped, untyped] arguments) -> String
71
- def self.queue_unbind: (Integer id, untyped queue, untyped exchange, untyped binding_key, Hash[untyped, untyped] arguments) -> String
72
- def self.queue_purge: (Integer id, untyped queue, bool no_wait) -> String
73
- def self.basic_get: (Integer id, untyped queue, bool no_ack) -> String
74
- def self.basic_publish: (Integer id, untyped exchange, untyped routing_key, bool mandatory) -> String
75
- def self.header: (Integer id, untyped body_size, Hash[(Symbol | String), untyped] properties) -> String
76
- def self.body: (Integer id, untyped body_part) -> String
77
- def self.basic_consume: (Integer id, String queue, String? tag, bool? no_ack, bool? exclusive, Hash[untyped, untyped]? arguments) -> String
78
- def self.basic_cancel: (Integer id, untyped consumer_tag, ?no_wait: bool) -> String
79
- def self.basic_cancel_ok: (Integer id, String consumer_tag) -> String
80
- def self.basic_ack: (Integer id, untyped delivery_tag, bool multiple) -> String
81
- def self.basic_nack: (Integer id, untyped delivery_tag, bool multiple, bool requeue) -> String
82
- def self.basic_reject: (Integer id, untyped delivery_tag, bool requeue) -> String
83
- def self.basic_qos: (Integer id, Integer? prefetch_size, Integer? prefetch_count, bool? global) -> String
84
- def self.basic_recover: (Integer id, untyped requeue) -> String
85
- def self.confirm_select: (Integer id, bool no_wait) -> String
86
- def self.tx_select: (Integer id) -> String
87
- def self.tx_commit: (Integer id) -> String
88
- def self.tx_rollback: (Integer id) -> String
89
- end
90
-
91
- class Message
92
- attr_reader channel(): Connection::Channel
93
- attr_reader delivery_tag(): Integer
94
- attr_reader exchange(): String
95
- attr_reader routing_key(): String
96
- attr_reader redelivered(): bool
97
- attr_reader consumer_tag(): String?
98
- attr_accessor properties(): Properties
99
- attr_accessor body(): String
100
- end
101
-
102
- class ReturnMessage
103
- attr_reader reply_code(): Integer
104
- attr_reader reply_text(): String
105
- attr_reader exchange(): String
106
- attr_reader routing_key(): String
107
- attr_accessor properties(): Properties
108
- attr_accessor body(): String
109
- end
110
-
111
- class Connection
112
- CLIENT_PROPERTIES: Hash[Symbol | String, untyped]
113
- @socket: (IO | untyped)
114
- @channel_max: Integer
115
- @heartbeat: Integer
116
- @channels: Hash[Integer, Channel]
117
- @closed: Array[untyped]?
118
- @replies: Thread::Queue
119
- @write_lock: Thread::Mutex
120
- @blocked: String?
121
- @id: Integer
122
-
123
- def initialize: (?String uri, ?read_loop_thread: bool, **untyped) -> void
124
- def self.connect: (?String uri, ?read_loop_thread: bool, **untyped) -> Connection
125
- attr_reader frame_max: Integer
126
- def inspect: -> String
127
- def channel: (?Integer? id) -> Channel
128
- def with_channel: { (Channel) -> void } -> void
129
- def close: (?reason: String, ?code: Integer) -> nil
130
- def closed?: -> bool
131
- def write_bytes: (*String bytes) -> Integer
132
- def read_loop: -> nil
133
-
134
- private
135
- def parse_frame: (Integer `type`, Integer channel_id, String buf) -> bool
136
- def expect: (:close_ok expected_frame_type) -> untyped
137
- def open_socket: (String host, Integer port, bool tls, Hash[Symbol, untyped] options) -> (IO | untyped)
138
- def establish: ((IO | untyped) socket, String user, String password, String vhost, Hash[Symbol, untyped] options) -> [Integer, Integer, Integer]
139
- def enable_tcp_keepalive: ((IO | untyped) socket) -> void
140
- def port_from_env: -> Integer?
141
-
142
- class Channel
143
- @connection: Connection
144
- @replies: Thread::Queue
145
- @consumers: Hash[String, Thread::Queue]
146
- @closed: Array[(:channel | :connection | Integer | String)]?
147
- @open: bool
148
- @on_return: nil
149
- @confirm: Integer?
150
- @unconfirmed: Thread::Queue
151
- @unconfirmed_empty: Thread::Queue
152
- @basic_gets: Thread::Queue
153
- @next_msg: (Message | ReturnMessage)?
154
- @next_body: StringIO?
155
- @next_body_size: (Float | Integer | String)?
156
-
157
- def initialize: (Connection connection, Integer? id) -> void
158
- def inspect: -> String
159
- attr_reader id: Integer?
160
- def open: -> Channel
161
- def close: (?reason: String, ?code: Integer) -> nil
162
- def closed!: (:channel | :connection level, (Float | Integer | String)? code, String reason, (Float | Integer | String)? classid, (Float | Integer | String)? methodid) -> nil
163
- def on_return: { (ReturnMessage) -> void } -> void
164
- def exchange_declare: (String name, String `type`, ?passive: bool, ?durable: bool, ?auto_delete: bool, ?internal: bool, ?arguments: Hash[untyped, untyped]) -> nil
165
- def exchange_delete: (String name, ?if_unused: bool, ?no_wait: bool) -> nil
166
- def exchange_bind: (String destination, String source, String binding_key, ?arguments: Hash[untyped, untyped]) -> nil
167
- def exchange_unbind: (String destination, String source, String binding_key, ?arguments: Hash[untyped, untyped]) -> nil
168
- def queue_declare: (?String name, ?passive: bool, ?durable: bool, ?exclusive: bool, ?auto_delete: bool, ?arguments: Hash[untyped, untyped]) -> QueueOk
169
- def queue_delete: (String name, ?if_unused: bool, ?if_empty: bool, ?no_wait: bool) -> Integer?
170
- def queue_bind: (String name, String exchange, String binding_key, ?arguments: Hash[untyped, untyped]) -> nil
171
- def queue_purge: (String name, ?no_wait: bool) -> nil
172
- def queue_unbind: (String name, String exchange, String binding_key, ?arguments: Hash[untyped, untyped]) -> nil
173
- def basic_get: (String queue_name, ?no_ack: bool) -> Message?
174
- def basic_publish: (String body, String exchange, String routing_key, **untyped) -> nil
175
- def basic_publish_confirm: (String body, String exchange, String routing_key, **untyped) -> bool
176
- def basic_consume: (String queue, ?tag: String, ?no_ack: bool?, ?exclusive: bool, ?arguments: Hash[untyped, untyped]?, ?worker_threads: Integer?) { (Message) -> void } -> [String, Array[Thread]]?
177
- def basic_cancel: (String consumer_tag, ?no_wait: bool) -> nil
178
- def basic_qos: (Integer prefetch_count, ?prefetch_size: Integer, ?global: bool) -> nil
179
- def basic_ack: (Integer delivery_tag, ?multiple: bool) -> nil
180
- def basic_nack: (Integer delivery_tag, ?multiple: bool, ?requeue: bool) -> nil
181
- def basic_reject: (Integer delivery_tag, ?requeue: bool) -> nil
182
- def basic_recover: (?requeue: bool) -> nil
183
- def confirm_select: (?no_wait: bool) -> nil
184
- def wait_for_confirms: -> bool
185
- def tx_select: -> nil
186
- def tx_commit: -> nil
187
- def tx_rollback: -> nil
188
- def reply: (Array[untyped] args) -> void
189
- def confirm: (Array[(:ack | :nack | Integer | bool)] args) -> nil
190
- def message_returned: ((Float | Integer | String)? reply_code, String reply_text, String exchange, String routing_key) -> ReturnMessage
191
- def message_delivered: (String? consumer_tag, (Float | Integer | String)? delivery_tag, bool redelivered, String exchange, String routing_key) -> Message
192
- def basic_get_empty: -> void
193
- def header_delivered: (Integer body_size, Properties properties) -> void
194
- def body_delivered: (String body_part) -> void
195
- def close_consumer: (String tag) -> nil
196
-
197
- private
198
- def next_message_finished!: -> void
199
- def write_bytes: (*String bytes) -> Integer
200
- def expect: (Symbol expected_frame_type) -> Array[untyped]
201
-
202
- class QueueOk < Struct[untyped]
203
- attr_accessor queue_name(): String
204
- attr_accessor message_count(): Integer
205
- attr_accessor consumer_count(): Integer
206
- end
207
- end
208
- end
209
-
210
- class Error < StandardError
211
- class UnexpectedFrame < Error
212
- def initialize: (Symbol expected, Symbol actual) -> void
213
- end
214
-
215
- class UnexpectedFrameEnd < Error
216
- def initialize: (untyped actual) -> void
217
- end
218
-
219
- class UnsupportedFrameType < Error
220
- def initialize: (untyped `type`) -> void
221
- end
222
-
223
- class UnsupportedMethodFrame < Error
224
- def initialize: (Integer class_id, Integer method_id) -> void
225
- end
226
-
227
- class Closed < Error
228
- def self.new: (Integer id, (:channel | :connection) level, Integer code, String reason, ?Integer classid, ?Integer methodid) -> (ChannelClosed | ConnectionClosed)
229
- end
230
-
231
- class ChannelClosed < Error
232
- def initialize: (Integer id, Integer code, String reason, ?Integer classid, ?Integer methodid) -> void
233
- end
234
-
235
- class ConnectionClosed < Error
236
- def initialize: (Integer code, String reason, ?Integer classid, ?Integer methodid) -> void
237
- end
238
- end
239
-
240
- class Exchange
241
- @client: Client
242
- @name: String
243
-
244
- def initialize: (Client client, String name) -> void
245
- def publish: (String body, String routing_key, **untyped) -> Exchange
246
- def bind: (String exchange, String binding_key, ?arguments: Hash[String | Symbol, untyped]) -> Exchange
247
- def unbind: (String exchange, String binding_key, ?arguments: Hash[String | Symbol, untyped]) -> Exchange
248
- def delete: -> nil
249
- end
250
-
251
- class Queue
252
- @client: Client
253
- @name: String
254
-
255
- def initialize: (Client client, String name) -> void
256
- def publish: (String body, **untyped) -> Queue
257
- def subscribe: (?no_ack: bool, ?prefetch: Integer, ?worker_threads: Integer, ?arguments: Hash[String | Symbol, untyped]) { (Message) -> void } -> Queue
258
- def bind: (String exchange, String binding_key, ?arguments: Hash[String | Symbol, untyped]) -> Queue
259
- def unbind: (String exchange, String binding_key, ?arguments: Hash[String | Symbol, untyped]) -> Queue
260
- def purge: -> Queue
261
- def delete: -> nil
262
- end
263
- end
264
- end