amqp-client 1.1.4 → 1.1.5

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: 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