queues-rabbit 0.1.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![](https://img.shields.io/static/v1?label=Language&message=Ruby&color=red)
|
3
|
+
![](https://img.shields.io/static/v1?label=Latest&message=0.1.0.beta&color=blue)
|
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
|