queues-rabbit 0.1.0.beta
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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +175 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +201 -0
- data/LICENSE.txt +21 -0
- data/README.md +456 -0
- data/Rakefile +12 -0
- data/lib/generators/queues_rabbit_generator.rb +26 -0
- data/lib/generators/templates/exchange.rb +13 -0
- data/lib/generators/templates/queue.rb +21 -0
- data/lib/generators/templates/schema.rb +8 -0
- data/lib/queues/rabbit/client.rb +7 -0
- data/lib/queues/rabbit/exchange.rb +88 -0
- data/lib/queues/rabbit/logger.rb +25 -0
- data/lib/queues/rabbit/message.rb +13 -0
- data/lib/queues/rabbit/queue.rb +117 -0
- data/lib/queues/rabbit/schema.rb +28 -0
- data/lib/queues/rabbit/version.rb +7 -0
- data/lib/queues/rabbit.rb +31 -0
- data/sig/queues/rabbit.rbs +6 -0
- metadata +95 -0
data/README.md
ADDED
@@ -0,0 +1,456 @@
|
|
1
|
+
# <img src="https://user-images.githubusercontent.com/50866745/156147715-d3773642-68c0-48c0-92ad-0ccc442ee881.svg" width="48"> Rails-Queues Rabbit
|
2
|
+

|
3
|
+

|
4
|
+
|
5
|
+
A Rails implementation of [RabbitMQ](https://www.rabbitmq.com/)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'queues-rabbit'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
```
|
18
|
+
bundle install
|
19
|
+
```
|
20
|
+
|
21
|
+
## Getting Started
|
22
|
+
|
23
|
+
The gem gets shipped with a scaffolding generator.
|
24
|
+
|
25
|
+
```
|
26
|
+
rails generate queues_rabbit
|
27
|
+
```
|
28
|
+
|
29
|
+
## Table of contents
|
30
|
+
|
31
|
+
* [Architecture](#architecture)
|
32
|
+
* [Rails Queues](#rails-queues)
|
33
|
+
* [Schema](#schema)
|
34
|
+
* [Queues](#queues)
|
35
|
+
* [Definition](#queue-definition)
|
36
|
+
* [Subscribing](#subscribing-a-queue)
|
37
|
+
* [Publishing](#publishing-to-queues)
|
38
|
+
* [Purge](#purge-a-queue)
|
39
|
+
* [Delete](#delete-a-queue)
|
40
|
+
* [Exchanges](#exchanges)
|
41
|
+
* [Definition](#exchange-definition)
|
42
|
+
* [Queue Binding](#queue-binding)
|
43
|
+
* [Queue Unbinding](#queue-unbinding)
|
44
|
+
* [Exchange Binding](#exchange-binding)
|
45
|
+
* [Exchange Unbinding](#exchange-unbinding)
|
46
|
+
* [Publishing](#publishing-to-an-exchange)
|
47
|
+
* [Delete](#delete-an-exchange)
|
48
|
+
* [Logging](#logging)
|
49
|
+
* [Usage Tips](#usage-tips)
|
50
|
+
|
51
|
+
|
52
|
+
## Architecture
|
53
|
+
|
54
|
+
The framework consists of a Schema where you can register your RabbitMQ Queues and Exchanges.
|
55
|
+
|
56
|
+
```
|
57
|
+
app
|
58
|
+
└── queues
|
59
|
+
├── application_queue.rb
|
60
|
+
└── rabbit
|
61
|
+
├── exchanges
|
62
|
+
│ └── my_exchange.rb
|
63
|
+
├── queues
|
64
|
+
│ └── my_queue.rb
|
65
|
+
└── schema.rb
|
66
|
+
```
|
67
|
+
|
68
|
+
## Rails-Queues
|
69
|
+
|
70
|
+
The gem belongs to the [Rails-Queues](https://github.com/LapoElisacci/queues) framework.
|
71
|
+
|
72
|
+
To initialize your RabbitMQ schema, add it to the `ApplicationQueue` class.
|
73
|
+
|
74
|
+
```Ruby
|
75
|
+
class ApplicationQueue < Queues::API
|
76
|
+
rabbit Rabbits::Schema, 'amqp://guest:guest@localhost'
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
You can have as many RabbitMQ instances to connect to as you want.
|
81
|
+
|
82
|
+
Each RabbitMQ instance must be attached to a specific Schema.
|
83
|
+
|
84
|
+
```Ruby
|
85
|
+
class ApplicationQueue < Queues::API
|
86
|
+
rabbit Rabbits::SchemaOne, 'amqp://guest:guest@localhost1'
|
87
|
+
rabbit Rabbits::SchemaTwo, 'amqp://guest:guest@localhost2'
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
## Schema
|
92
|
+
|
93
|
+
The Schema allows you to regiter both the queues and the exchanges.
|
94
|
+
|
95
|
+
```Ruby
|
96
|
+
module Rabbits
|
97
|
+
class Schema < ::Queues::Rabbit::Schema
|
98
|
+
queue Rabbits::Queues::MyQueue
|
99
|
+
exchange Rabbits::Queues::MyExchange
|
100
|
+
end
|
101
|
+
end
|
102
|
+
```
|
103
|
+
|
104
|
+
You can register as many queues and exchanges as you need.
|
105
|
+
|
106
|
+
```Ruby
|
107
|
+
module Rabbits
|
108
|
+
class Schema < ::Queues::Rabbit::Schema
|
109
|
+
queue Rabbits::Queues::MyQueueOne
|
110
|
+
exchange Rabbits::Queues::MyExchangeOne
|
111
|
+
|
112
|
+
queue Rabbits::Queues::MyQueueTwo
|
113
|
+
exchange Rabbits::Queues::MyExchangeTwo
|
114
|
+
end
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
## Queues
|
119
|
+
|
120
|
+
Each queue can be declared by a class that inherits from `Queues::Rabbit::Queue`
|
121
|
+
|
122
|
+
### Queue Definition
|
123
|
+
|
124
|
+
```Ruby
|
125
|
+
module Rabbits
|
126
|
+
module Queues
|
127
|
+
class MyQueue < ::Queues::Rabbit::Queue
|
128
|
+
queue 'my.queue',
|
129
|
+
auto_ack: true,
|
130
|
+
auto_delete: false,
|
131
|
+
durable: true,
|
132
|
+
prefetch: 1,
|
133
|
+
arguments: {}
|
134
|
+
|
135
|
+
# ...
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
The `queue` method allows you to define the RabbitMQ queue parameters.
|
142
|
+
|
143
|
+
- The queue name
|
144
|
+
- **auto_ack:** When false messages have to be manually acknowledged (or rejected)
|
145
|
+
- **auto_delete:** If true, the queue will be deleted when the last consumer stops consuming.
|
146
|
+
- **durable:** If true, the queue will survive broker restarts, messages in the queue will only survive if they are published as persistent.
|
147
|
+
- **prefetch:** Specify how many messages to prefetch for consumers (with no_ack is false)
|
148
|
+
- **arguments:** Custom arguments, such as queue-ttl etc.
|
149
|
+
|
150
|
+
Params **durable**, **auto_delete** and **arguments** are optional, default values are:
|
151
|
+
- **durable:** true
|
152
|
+
- **auto_delete:** false
|
153
|
+
- **arguments:** {}
|
154
|
+
|
155
|
+
(Remember to register the queue class to the Schema, more details [here](#schema))
|
156
|
+
|
157
|
+
### Subscribing a queue
|
158
|
+
|
159
|
+
To compute a message when it gets received, define a method called `consume` inside your queue Class, like so:
|
160
|
+
|
161
|
+
```Ruby
|
162
|
+
module Rabbits
|
163
|
+
module Queues
|
164
|
+
class MyQueue < ::Queues::Rabbit::Queue
|
165
|
+
queue 'my.queue',
|
166
|
+
auto_ack: true,
|
167
|
+
auto_delete: false,
|
168
|
+
durable: true,
|
169
|
+
prefetch: 1,
|
170
|
+
arguments: {}
|
171
|
+
|
172
|
+
def consume(message)
|
173
|
+
# do something with the message
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
```
|
179
|
+
|
180
|
+
The messange param is a `Queues::Rabbit::Message` instance where you can access the following properties:
|
181
|
+
|
182
|
+
- **body:** The message body.
|
183
|
+
- **consumer_tag:** The RabbitMQ consumer associated tag.
|
184
|
+
- **delivery_tag:** The RabbitMQ delivery tag.
|
185
|
+
- **exchange:** The exchange name (Empty for default exchange).
|
186
|
+
|
187
|
+
The `Queues::Rabbit::Message` also implements a few interesting methods:
|
188
|
+
|
189
|
+
- **ack:** Allows you to manually acknoledge the message (When **auto_ack** is set to **false**)
|
190
|
+
- **reject:** Allows you to manually reject a message (it accepts an argument **requeue** that if true the message will be put back into the queue)
|
191
|
+
|
192
|
+
```Ruby
|
193
|
+
module Rabbits
|
194
|
+
module Queues
|
195
|
+
class MyQueue < ::Queues::Rabbit::Queue
|
196
|
+
queue 'my.queue',
|
197
|
+
auto_ack: false,
|
198
|
+
|
199
|
+
def consume(message)
|
200
|
+
puts message.body
|
201
|
+
message.ack
|
202
|
+
rescue
|
203
|
+
message.reject(requeue: false)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
```
|
209
|
+
|
210
|
+
### WARNING
|
211
|
+
|
212
|
+
The **consume** method will get executed inside a separated thread, make sure it's threadsafe!
|
213
|
+
|
214
|
+
After defining the **consume** method, to subscribe the queue call the, call the **subscribe** method, like so:
|
215
|
+
|
216
|
+
```Ruby
|
217
|
+
Rabbits::Queues::MyQueue.subscribe
|
218
|
+
```
|
219
|
+
|
220
|
+
The method won't return until the connection gets closed.
|
221
|
+
Aliveness logs will get printed to **STDOUT**.
|
222
|
+
|
223
|
+
### Publishing to queues
|
224
|
+
|
225
|
+
To publish a message into a declared queue, call the **publish** method:
|
226
|
+
|
227
|
+
```Ruby
|
228
|
+
Rabbits::Queues::MyQueue.publish({ foo: 'bar' }.to_json, content_type: 'application/json')
|
229
|
+
```
|
230
|
+
|
231
|
+
The **publish** method accepts several options, here's the method documentation:
|
232
|
+
|
233
|
+
```Ruby
|
234
|
+
# @param [String] body The message body, can be a string or either a byte array
|
235
|
+
# @param [Hash] properties Request properties
|
236
|
+
# @option properties [String] :app_id Used to identify the app that generated the message
|
237
|
+
# @option properties [String] :content_encoding Content encoding of the body
|
238
|
+
# @option properties [String] :content_type Content type of the body
|
239
|
+
# @option properties [Integer] :correlation_id The correlation id, mostly used used for RPC communication
|
240
|
+
# @option properties [Integer] :delivery_mode 2 for persistent messages, all other values are for transient messages
|
241
|
+
# @option properties [Integer, String] :expiration Number of seconds the message will stay in the queue
|
242
|
+
# @option properties [Hash<String, Object>] :headers Custom headers
|
243
|
+
# @option properties [Boolean] :mandatory The message will be returned if the message can't be routed to a queue
|
244
|
+
# @option properties [String] :message_id Can be used to uniquely identify the message, e.g. for deduplication
|
245
|
+
# @option properties [Boolean] :persistent Same as delivery_mode: 2
|
246
|
+
# @option properties [Integer] :priority The message priority (between 0 and 255)
|
247
|
+
# @option properties [String] :reply_to Queue to reply RPC responses to
|
248
|
+
# @option properties [Date] :timestamp Often used for the time the message was originally generated
|
249
|
+
# @option properties [String] :type Can indicate what kind of message this is
|
250
|
+
# @option properties [String] :user_id Used to identify the user that published the message
|
251
|
+
#
|
252
|
+
# @return [Boolean] true if published, false otherwise
|
253
|
+
#
|
254
|
+
def publish(body, **properties)
|
255
|
+
```
|
256
|
+
|
257
|
+
### Purge a queue
|
258
|
+
|
259
|
+
To purge all messages from a defined queue, call the **purge** method, like so:
|
260
|
+
|
261
|
+
```Ruby
|
262
|
+
Rabbits::Queues::MyQueue.purge
|
263
|
+
```
|
264
|
+
|
265
|
+
### Delete a queue
|
266
|
+
|
267
|
+
To delete a queue from RabbitMQ, call the **delete** method, like so:
|
268
|
+
|
269
|
+
```Ruby
|
270
|
+
Rabbits::Queues::MyQueue.delete
|
271
|
+
```
|
272
|
+
|
273
|
+
## Exchanges
|
274
|
+
|
275
|
+
Just like queues, exchanges must be declared by a class that inherits, this time, from `Queues::Rabbit::Exchange`
|
276
|
+
|
277
|
+
### Exchange Definition
|
278
|
+
|
279
|
+
```Ruby
|
280
|
+
module Rabbits
|
281
|
+
module Exchanges
|
282
|
+
class MyExchange < ::Queues::Rabbit::Exchange
|
283
|
+
exchange 'my.exchange', 'direct',
|
284
|
+
auto_delete: false,
|
285
|
+
durable: true,
|
286
|
+
internal: false,
|
287
|
+
arguments: {}
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
```
|
292
|
+
|
293
|
+
The `exchange` method allows you to define the exchange parameters.
|
294
|
+
|
295
|
+
- The exchange name
|
296
|
+
- The exchange type ('direct', 'fanout', 'headers', 'topic' ...)
|
297
|
+
- **auto_delete:** If true, the exchange will be deleted when the last queue/exchange gets unbounded.
|
298
|
+
- **durable:** If true, the exchange will persist between broker restarts, also a required for persistent messages.
|
299
|
+
- **internal:** If true, the messages can't be pushed directly to the exchange.
|
300
|
+
- **arguments:** Custom exchange arguments.
|
301
|
+
|
302
|
+
(Remember to register the exchange class to the Schema, more details [here](#schema))
|
303
|
+
|
304
|
+
### Queue binding
|
305
|
+
|
306
|
+
To bind a queue to an exchange, call the **bind** method inside the queue class, like so:
|
307
|
+
|
308
|
+
```Ruby
|
309
|
+
module Rabbits
|
310
|
+
module Queues
|
311
|
+
class MyQueue < ::Queues::Rabbit::Queue
|
312
|
+
queue 'my.queue',
|
313
|
+
auto_ack: true,
|
314
|
+
auto_delete: false,
|
315
|
+
durable: true,
|
316
|
+
prefetch: 1,
|
317
|
+
arguments: {}
|
318
|
+
|
319
|
+
bind Rabbits::Exchanges::MyExchange, 'my.binding.key', arguments: {}
|
320
|
+
|
321
|
+
# ...
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
```
|
326
|
+
|
327
|
+
You can also statically declare the exchange name, like so:
|
328
|
+
|
329
|
+
```Ruby
|
330
|
+
bind 'my.exchange', 'my.binding.key', arguments: {}
|
331
|
+
```
|
332
|
+
|
333
|
+
The `bind` method allows you to define the queue-exchange binding parameters.
|
334
|
+
|
335
|
+
- The exchange name
|
336
|
+
- The binding key
|
337
|
+
- **arguments:** Message headers to match on (only relevant for header exchanges)
|
338
|
+
|
339
|
+
### Queue unbinding
|
340
|
+
|
341
|
+
To unbind a queue from an exchange call the **unbind** method, like so:
|
342
|
+
|
343
|
+
```Ruby
|
344
|
+
Rabbits::Queues::MyQueue.unbind(Rabbits::Exchanges::MyExchange, 'my.binding.key', arguments: {})
|
345
|
+
```
|
346
|
+
|
347
|
+
or
|
348
|
+
|
349
|
+
```Ruby
|
350
|
+
Rabbits::Queues::MyQueue.unbind('my.exchange', 'my.binding.key', arguments: {})
|
351
|
+
```
|
352
|
+
|
353
|
+
### Exchange binding
|
354
|
+
|
355
|
+
To bind an exchange to another exchange, call the **bind** method inside the exchange class, like so:
|
356
|
+
|
357
|
+
```Ruby
|
358
|
+
module Rabbits
|
359
|
+
module Exchanges
|
360
|
+
class MyExchange < ::Queues::Rabbit::Exchange
|
361
|
+
exchange 'my.exchange', 'direct',
|
362
|
+
auto_delete: false,
|
363
|
+
durable: true,
|
364
|
+
internal: false,
|
365
|
+
arguments: {}
|
366
|
+
|
367
|
+
bind Rabbits::Exchanges::MyExchangeTwo, 'my.binding.key', arguments: {}
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
```
|
372
|
+
|
373
|
+
### Exchange unbinding
|
374
|
+
|
375
|
+
To unbind an exchange from another exchange call the **unbind** method, like so:
|
376
|
+
|
377
|
+
```Ruby
|
378
|
+
Rabbits::Exchanges::MyExchange.unbind(Rabbits::Exchanges::MyExchangeTwo, 'my.binding.key', arguments: {})
|
379
|
+
```
|
380
|
+
|
381
|
+
or
|
382
|
+
|
383
|
+
```Ruby
|
384
|
+
Rabbits::Exchanges::MyExchange.unbind('my.exchange.two', 'my.binding.key', arguments: {})
|
385
|
+
```
|
386
|
+
|
387
|
+
### Publishing to an exchange
|
388
|
+
|
389
|
+
To publish a message to an exchange call the **publish** method, like so:
|
390
|
+
|
391
|
+
```Ruby
|
392
|
+
Rabbits::Exchanges::MyExchange.publish('my message', 'my.routing.key', properties: {})
|
393
|
+
```
|
394
|
+
|
395
|
+
The **publish** method accepts several options, here's the method documentation:
|
396
|
+
|
397
|
+
```Ruby
|
398
|
+
# @param [String] body The message body, can be a string or either a byte array
|
399
|
+
# @param [String] routing_key The routing key to route the message to bounded queues
|
400
|
+
# @param [Hash] properties Request properties
|
401
|
+
# @option properties [String] :app_id Used to identify the app that generated the message
|
402
|
+
# @option properties [String] :content_encoding Content encoding of the body
|
403
|
+
# @option properties [String] :content_type Content type of the body
|
404
|
+
# @option properties [Integer] :correlation_id The correlation id, mostly used used for RPC communication
|
405
|
+
# @option properties [Integer] :delivery_mode 2 for persistent messages, all other values are for transient messages
|
406
|
+
# @option properties [Integer, String] :expiration Number of seconds the message will stay in the queue
|
407
|
+
# @option properties [Hash<String, Object>] :headers Custom headers
|
408
|
+
# @option properties [Boolean] :mandatory The message will be returned if the message can't be routed to a queue
|
409
|
+
# @option properties [String] :message_id Can be used to uniquely identify the message, e.g. for deduplication
|
410
|
+
# @option properties [Boolean] :persistent Same as delivery_mode: 2
|
411
|
+
# @option properties [Integer] :priority The message priority (between 0 and 255)
|
412
|
+
# @option properties [String] :reply_to Queue to reply RPC responses to
|
413
|
+
# @option properties [Date] :timestamp Often used for the time the message was originally generated
|
414
|
+
# @option properties [String] :type Can indicate what kind of message this is
|
415
|
+
# @option properties [String] :user_id Used to identify the user that published the message
|
416
|
+
#
|
417
|
+
# @return [Boolean] true if published, false otherwise
|
418
|
+
#
|
419
|
+
def publish(body, routing_key, **properties)
|
420
|
+
```
|
421
|
+
|
422
|
+
### Delete an exchange
|
423
|
+
|
424
|
+
To delete an exchange from RabbitMQ call the **delete** method, like so:
|
425
|
+
|
426
|
+
```Ruby
|
427
|
+
Rabbits::Exchanges::MyExchange.delete
|
428
|
+
```
|
429
|
+
|
430
|
+
## Logging
|
431
|
+
|
432
|
+
Queues and Exchanges have a built-in logger.
|
433
|
+
|
434
|
+
Each queue and each exchange will have its log file inside the `log` directory. The filename will match the queue/exchange name.
|
435
|
+
|
436
|
+
While [consuming messages from a queue](#subscribing-a-queue), logs will also get pushed to `STDOUT`.
|
437
|
+
|
438
|
+
## Usage tips
|
439
|
+
|
440
|
+
A good way to implement queues subscription is to use [Rails runners](https://guides.rubyonrails.org/command_line.html#bin-rails-runner) to spawn a specific process for each connection.
|
441
|
+
|
442
|
+
```Bash
|
443
|
+
rails runner -e production "Rabbits::Queues::MyQueue.subscribe"
|
444
|
+
```
|
445
|
+
|
446
|
+
## Contributing
|
447
|
+
|
448
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/LapoElisacci/queues-rabbit.
|
449
|
+
|
450
|
+
## Credits
|
451
|
+
|
452
|
+
The gem is based on the amazing RabbitMQ client by [cloudamqp](https://github.com/cloudamqp/amqp-client.rb).
|
453
|
+
|
454
|
+
## License
|
455
|
+
|
456
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
|
5
|
+
# Creates the Queues initializer file for Rails apps.
|
6
|
+
#
|
7
|
+
# @example Invokation from terminal
|
8
|
+
# rails generate queues_rabbit
|
9
|
+
#
|
10
|
+
class QueuesRabbitGenerator < Rails::Generators::Base
|
11
|
+
desc "Description:\n This prepares Rails for RabbitMQ Queues"
|
12
|
+
|
13
|
+
source_root File.expand_path('templates', __dir__)
|
14
|
+
|
15
|
+
desc 'Initialize Rails for RabbitMQ Queues'
|
16
|
+
|
17
|
+
def generate_layout
|
18
|
+
if !File.exist?('app/queues/application_queue.rb')
|
19
|
+
generate 'queues'
|
20
|
+
end
|
21
|
+
|
22
|
+
template 'schema.rb', 'app/queues/rabbits/schema.rb'
|
23
|
+
template 'queue.rb', 'app/queues/rabbits/queues/my_queue.rb'
|
24
|
+
template 'exchange.rb', 'app/queues/rabbits/exchanges/my_exchange.rb'
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rabbits
|
4
|
+
module Exchanges
|
5
|
+
class MyExchange < ::Queues::Rabbit::Exchange
|
6
|
+
exchange 'my.exchange', 'direct', # Required
|
7
|
+
durable: true, # Optional
|
8
|
+
auto_delete: false, # Optional
|
9
|
+
internal: false, # Optional
|
10
|
+
arguments: {} # Optional
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rabbits
|
4
|
+
module Queues
|
5
|
+
class MyQueue < ::Queues::Rabbit::Queue
|
6
|
+
queue 'my.queue', # Required
|
7
|
+
auto_ack: false, # Optional
|
8
|
+
auto_delete: false, # Optional
|
9
|
+
durable: true, # Optional
|
10
|
+
prefetch: 1, # Optional
|
11
|
+
arguments: {} # Optional
|
12
|
+
|
13
|
+
def consume(message)
|
14
|
+
# do something with the message
|
15
|
+
message.ack
|
16
|
+
rescue
|
17
|
+
message.reject(requeue: false)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Queues
|
4
|
+
module Rabbit
|
5
|
+
class Exchange
|
6
|
+
class << self
|
7
|
+
attr_accessor :arguments, :auto_delete, :durable, :internal, :name, :schema, :type
|
8
|
+
|
9
|
+
def bind(exchange, binding_key, arguments: {})
|
10
|
+
exchange = exchange < Queues::Rabbit::Exchange ? exchange.name : exchange
|
11
|
+
exchange_instance.bind(exchange, binding_key, arguments: arguments)
|
12
|
+
true
|
13
|
+
rescue Exception => e
|
14
|
+
logger.error_with_report "Unable to bind '#{name}' to '#{exchange}' with key '#{binding_key}' and arguments: '#{arguments}': #{e.message}."
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete
|
19
|
+
exchange_instance.delete
|
20
|
+
true
|
21
|
+
rescue Exception => e
|
22
|
+
logger.error_with_report "Unable to delete #{name}: #{e.message}."
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def exchange(name, type, arguments: {}, auto_delete: false, durable: true, internal: false)
|
27
|
+
self.arguments = arguments
|
28
|
+
self.auto_delete = auto_delete
|
29
|
+
self.name = name
|
30
|
+
self.durable = durable
|
31
|
+
self.internal = internal
|
32
|
+
self.name = name
|
33
|
+
self.type = type
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def exchange_instance
|
38
|
+
@@exchange_instance ||= schema.client_instance.exchange(name, type, arguments: arguments, auto_delete: auto_delete, durable: durable, internal: internal)
|
39
|
+
end
|
40
|
+
|
41
|
+
def logger
|
42
|
+
@@logger ||= Queues::Rabbit::Logger.new(name, Queues::Rabbit.log_level)
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# <Description>
|
47
|
+
#
|
48
|
+
# @param [String] body The message body, can be a string or either a byte array
|
49
|
+
# @param [String] routing_key The routing key to route the message to bounded queues
|
50
|
+
# @param [Hash] properties Request properties
|
51
|
+
# @option properties [String] :app_id Used to identify the app that generated the message
|
52
|
+
# @option properties [String] :content_encoding Content encoding of the body
|
53
|
+
# @option properties [String] :content_type Content type of the body
|
54
|
+
# @option properties [Integer] :correlation_id The correlation id, mostly used used for RPC communication
|
55
|
+
# @option properties [Integer] :delivery_mode 2 for persistent messages, all other values are for transient messages
|
56
|
+
# @option properties [Integer, String] :expiration Number of seconds the message will stay in the queue
|
57
|
+
# @option properties [Hash<String, Object>] :headers Custom headers
|
58
|
+
# @option properties [Boolean] :mandatory The message will be returned if the message can't be routed to a queue
|
59
|
+
# @option properties [String] :message_id Can be used to uniquely identify the message, e.g. for deduplication
|
60
|
+
# @option properties [Boolean] :persistent Same as delivery_mode: 2
|
61
|
+
# @option properties [Integer] :priority The message priority (between 0 and 255)
|
62
|
+
# @option properties [String] :reply_to Queue to reply RPC responses to
|
63
|
+
# @option properties [Date] :timestamp Often used for the time the message was originally generated
|
64
|
+
# @option properties [String] :type Can indicate what kind of message this is
|
65
|
+
# @option properties [String] :user_id Used to identify the user that published the message
|
66
|
+
#
|
67
|
+
# @return [Boolean] true if published, false otherwise
|
68
|
+
#
|
69
|
+
def publish(body, routing_key, **properties)
|
70
|
+
exchange_instance.publish(body, name, routing_key, **properties)
|
71
|
+
true
|
72
|
+
rescue Exception => e
|
73
|
+
logger.error_with_report "Unable to publish to #{name}: #{e.message}."
|
74
|
+
false
|
75
|
+
end
|
76
|
+
|
77
|
+
def unbind(exchange, binding_key, arguments: {})
|
78
|
+
exchange = exchange < Queues::Rabbit::Exchange ? exchange.name : exchange
|
79
|
+
exchange_instance.unbind(exchange, binding_key, arguments: arguments)
|
80
|
+
true
|
81
|
+
rescue Exception => e
|
82
|
+
logger.error_with_report "Unable to unbind '#{name}' to '#{exchange}' with key '#{binding_key}' and arguments: '#{arguments}': #{e.message}."
|
83
|
+
false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_litteral: true
|
2
|
+
|
3
|
+
module Queues
|
4
|
+
module Rabbit
|
5
|
+
class Logger
|
6
|
+
delegate :unknown, :fatal, :error, :warn, :info, :debug, to: :@logger
|
7
|
+
|
8
|
+
def initialize(name, level)
|
9
|
+
@logger = ::Logger.new("log/#{name}.log")
|
10
|
+
@logger.level = level
|
11
|
+
@std = ::Logger.new(STDOUT)
|
12
|
+
@std.level = ::Logger::INFO
|
13
|
+
end
|
14
|
+
|
15
|
+
def error_with_report(message)
|
16
|
+
@logger.error { message }
|
17
|
+
@logger.error { 'Please report to https://github.com/LapoElisacci/queues-rabbit if needed.' }
|
18
|
+
end
|
19
|
+
|
20
|
+
def stdout(message, level = :info)
|
21
|
+
@std.send(level, message)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Queues
|
4
|
+
module Rabbit
|
5
|
+
class Message < AMQP::Client::Message
|
6
|
+
def initialize(message)
|
7
|
+
message.instance_variables.each do |variable|
|
8
|
+
instance_variable_set(variable, message.instance_variable_get(variable))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|