queues-rabbit 0.1.0.beta.1 → 0.1.0.pre
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 +4 -4
- data/CHANGELOG.md +4 -2
- data/README.md +13 -441
- data/lib/queues/rabbit/version.rb +1 -1
- data/lib/queues/rabbit.rb +2 -22
- metadata +5 -45
- data/Gemfile.lock +0 -201
- data/lib/generators/queues_rabbit_generator.rb +0 -26
- data/lib/generators/templates/exchange.rb +0 -13
- data/lib/generators/templates/queue.rb +0 -30
- data/lib/generators/templates/schema.rb +0 -8
- data/lib/queues/rabbit/client.rb +0 -10
- data/lib/queues/rabbit/exchange.rb +0 -135
- data/lib/queues/rabbit/logger.rb +0 -36
- data/lib/queues/rabbit/message.rb +0 -16
- data/lib/queues/rabbit/queue.rb +0 -222
- data/lib/queues/rabbit/schema.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c930c4cfd93c6105dd18aa21506ec445a4474fda860b42c8efc8b591a612bd97
|
4
|
+
data.tar.gz: 386851ffc9733ecaab369562ad12b46dc5a53744b27d169dd5d52369174def7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 513a088c0cb63c77e629a1f68d84c10978a28f646d564b0d71e6d6a478b3ead1d7cdebd06679b711dd296a06943cdad6d6e6bfe01a37e86db5a4d468b4b49186
|
7
|
+
data.tar.gz: d90d46e6e55fb2499c33bd8bb5d37a30306d4c8e1a938a481e44769efd04e7d856a685311a77a0738546c7fc85ad8c16cf924874f405d0275f90c26819f76d89
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#
|
2
|
-

|
3
|
-

|
1
|
+
# Queues::Rabbit
|
4
2
|
|
5
|
-
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/queues/rabbit`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -14,453 +14,25 @@ gem 'queues-rabbit'
|
|
14
14
|
|
15
15
|
And then execute:
|
16
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.
|
148
|
-
- **arguments:** Custom arguments, such as queue-ttl etc.
|
149
|
-
|
150
|
-
Params **auto_ack**, **auto_delete**, **durable**, **prefetch** and **arguments** are optional, default values are:
|
151
|
-
- **auto_ack:** true
|
152
|
-
- **auto_delete:** false
|
153
|
-
- **durable:** true
|
154
|
-
- **prefetch:** 1
|
155
|
-
- **arguments:** {}
|
17
|
+
$ bundle install
|
156
18
|
|
157
|
-
|
19
|
+
Or install it yourself as:
|
158
20
|
|
159
|
-
|
21
|
+
$ gem install queues-rabbit
|
160
22
|
|
161
|
-
|
23
|
+
## Usage
|
162
24
|
|
163
|
-
|
164
|
-
module Rabbits
|
165
|
-
module Queues
|
166
|
-
class MyQueue < ::Queues::Rabbit::Queue
|
167
|
-
queue 'my.queue',
|
168
|
-
auto_ack: true,
|
169
|
-
auto_delete: false,
|
170
|
-
durable: true,
|
171
|
-
prefetch: 1,
|
172
|
-
arguments: {}
|
25
|
+
TODO: Write usage instructions here
|
173
26
|
|
174
|
-
|
175
|
-
# do something with the message
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
```
|
181
|
-
|
182
|
-
The messange param is a `Queues::Rabbit::Message` instance where you can access the following properties:
|
183
|
-
|
184
|
-
- **body:** The message body.
|
185
|
-
- **consumer_tag:** The RabbitMQ consumer associated tag.
|
186
|
-
- **delivery_tag:** The RabbitMQ delivery tag.
|
187
|
-
- **exchange:** The exchange name (Empty for default exchange).
|
188
|
-
|
189
|
-
The `Queues::Rabbit::Message` also implements a few interesting methods:
|
190
|
-
|
191
|
-
- **ack:** Allows you to manually acknoledge the message (When **auto_ack** is set to **false**)
|
192
|
-
- **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)
|
193
|
-
|
194
|
-
```Ruby
|
195
|
-
module Rabbits
|
196
|
-
module Queues
|
197
|
-
class MyQueue < ::Queues::Rabbit::Queue
|
198
|
-
queue 'my.queue',
|
199
|
-
auto_ack: false,
|
200
|
-
|
201
|
-
def consume(message)
|
202
|
-
puts message.body
|
203
|
-
message.ack
|
204
|
-
rescue
|
205
|
-
message.reject(requeue: false)
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
```
|
27
|
+
## Development
|
211
28
|
|
212
|
-
|
213
|
-
|
214
|
-
The **consume** method will get executed inside a separated thread, make sure it's threadsafe!
|
215
|
-
|
216
|
-
After defining the **consume** method, to subscribe the queue call the, call the **subscribe** method, like so:
|
217
|
-
|
218
|
-
```Ruby
|
219
|
-
Rabbits::Queues::MyQueue.subscribe
|
220
|
-
```
|
221
|
-
|
222
|
-
The method won't return until the connection gets closed.
|
223
|
-
Aliveness logs will get printed to **STDOUT**.
|
224
|
-
|
225
|
-
### Publishing to queues
|
226
|
-
|
227
|
-
To publish a message into a declared queue, call the **publish** method:
|
228
|
-
|
229
|
-
```Ruby
|
230
|
-
Rabbits::Queues::MyQueue.publish({ foo: 'bar' }.to_json, content_type: 'application/json')
|
231
|
-
```
|
232
|
-
|
233
|
-
The **publish** method accepts several options, here's the method documentation:
|
234
|
-
|
235
|
-
```Ruby
|
236
|
-
# @param [String] body The message body, can be a string or either a byte array
|
237
|
-
# @param [Hash] properties Request properties
|
238
|
-
# @option properties [String] :app_id Used to identify the app that generated the message
|
239
|
-
# @option properties [String] :content_encoding Content encoding of the body
|
240
|
-
# @option properties [String] :content_type Content type of the body
|
241
|
-
# @option properties [Integer] :correlation_id The correlation id, mostly used used for RPC communication
|
242
|
-
# @option properties [Integer] :delivery_mode 2 for persistent messages, all other values are for transient messages
|
243
|
-
# @option properties [Integer, String] :expiration Number of seconds the message will stay in the queue
|
244
|
-
# @option properties [Hash<String, Object>] :headers Custom headers
|
245
|
-
# @option properties [Boolean] :mandatory The message will be returned if the message can't be routed to a queue
|
246
|
-
# @option properties [String] :message_id Can be used to uniquely identify the message, e.g. for deduplication
|
247
|
-
# @option properties [Boolean] :persistent Same as delivery_mode: 2
|
248
|
-
# @option properties [Integer] :priority The message priority (between 0 and 255)
|
249
|
-
# @option properties [String] :reply_to Queue to reply RPC responses to
|
250
|
-
# @option properties [Date] :timestamp Often used for the time the message was originally generated
|
251
|
-
# @option properties [String] :type Can indicate what kind of message this is
|
252
|
-
# @option properties [String] :user_id Used to identify the user that published the message
|
253
|
-
#
|
254
|
-
# @return [Boolean] true if published, false otherwise
|
255
|
-
#
|
256
|
-
def publish(body, **properties)
|
257
|
-
```
|
258
|
-
|
259
|
-
### Purge a queue
|
260
|
-
|
261
|
-
To purge all messages from a defined queue, call the **purge** method, like so:
|
262
|
-
|
263
|
-
```Ruby
|
264
|
-
Rabbits::Queues::MyQueue.purge
|
265
|
-
```
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
266
30
|
|
267
|
-
|
268
|
-
|
269
|
-
To delete a queue from RabbitMQ, call the **delete** method, like so:
|
270
|
-
|
271
|
-
```Ruby
|
272
|
-
Rabbits::Queues::MyQueue.delete
|
273
|
-
```
|
274
|
-
|
275
|
-
## Exchanges
|
276
|
-
|
277
|
-
Just like queues, exchanges must be declared by a class that inherits, this time, from `Queues::Rabbit::Exchange`
|
278
|
-
|
279
|
-
### Exchange Definition
|
280
|
-
|
281
|
-
```Ruby
|
282
|
-
module Rabbits
|
283
|
-
module Exchanges
|
284
|
-
class MyExchange < ::Queues::Rabbit::Exchange
|
285
|
-
exchange 'my.exchange', 'direct',
|
286
|
-
auto_delete: false,
|
287
|
-
durable: true,
|
288
|
-
internal: false,
|
289
|
-
arguments: {}
|
290
|
-
end
|
291
|
-
end
|
292
|
-
end
|
293
|
-
```
|
294
|
-
|
295
|
-
The `exchange` method allows you to define the exchange parameters.
|
296
|
-
|
297
|
-
- The exchange name
|
298
|
-
- The exchange type ('direct', 'fanout', 'headers', 'topic' ...)
|
299
|
-
- **auto_delete:** If true, the exchange will be deleted when the last queue/exchange gets unbounded.
|
300
|
-
- **durable:** If true, the exchange will persist between broker restarts, also a required for persistent messages.
|
301
|
-
- **internal:** If true, the messages can't be pushed directly to the exchange.
|
302
|
-
- **arguments:** Custom exchange arguments.
|
303
|
-
|
304
|
-
(Remember to register the exchange class to the Schema, more details [here](#schema))
|
305
|
-
|
306
|
-
### Queue binding
|
307
|
-
|
308
|
-
To bind a queue to an exchange, call the **bind** method inside the queue class, like so:
|
309
|
-
|
310
|
-
```Ruby
|
311
|
-
module Rabbits
|
312
|
-
module Queues
|
313
|
-
class MyQueue < ::Queues::Rabbit::Queue
|
314
|
-
queue 'my.queue',
|
315
|
-
auto_ack: true,
|
316
|
-
auto_delete: false,
|
317
|
-
durable: true,
|
318
|
-
prefetch: 1,
|
319
|
-
arguments: {}
|
320
|
-
|
321
|
-
bind Rabbits::Exchanges::MyExchange, 'my.binding.key', arguments: {}
|
322
|
-
|
323
|
-
# ...
|
324
|
-
end
|
325
|
-
end
|
326
|
-
end
|
327
|
-
```
|
328
|
-
|
329
|
-
You can also statically declare the exchange name, like so:
|
330
|
-
|
331
|
-
```Ruby
|
332
|
-
bind 'my.exchange', 'my.binding.key', arguments: {}
|
333
|
-
```
|
334
|
-
|
335
|
-
The `bind` method allows you to define the queue-exchange binding parameters.
|
336
|
-
|
337
|
-
- The exchange name
|
338
|
-
- The binding key
|
339
|
-
- **arguments:** Message headers to match on (only relevant for header exchanges)
|
340
|
-
|
341
|
-
### Queue unbinding
|
342
|
-
|
343
|
-
To unbind a queue from an exchange call the **unbind** method, like so:
|
344
|
-
|
345
|
-
```Ruby
|
346
|
-
Rabbits::Queues::MyQueue.unbind(Rabbits::Exchanges::MyExchange, 'my.binding.key', arguments: {})
|
347
|
-
```
|
348
|
-
|
349
|
-
or
|
350
|
-
|
351
|
-
```Ruby
|
352
|
-
Rabbits::Queues::MyQueue.unbind('my.exchange', 'my.binding.key', arguments: {})
|
353
|
-
```
|
354
|
-
|
355
|
-
### Exchange binding
|
356
|
-
|
357
|
-
To bind an exchange to another exchange, call the **bind** method inside the exchange class, like so:
|
358
|
-
|
359
|
-
```Ruby
|
360
|
-
module Rabbits
|
361
|
-
module Exchanges
|
362
|
-
class MyExchange < ::Queues::Rabbit::Exchange
|
363
|
-
exchange 'my.exchange', 'direct',
|
364
|
-
auto_delete: false,
|
365
|
-
durable: true,
|
366
|
-
internal: false,
|
367
|
-
arguments: {}
|
368
|
-
|
369
|
-
bind Rabbits::Exchanges::MyExchangeTwo, 'my.binding.key', arguments: {}
|
370
|
-
end
|
371
|
-
end
|
372
|
-
end
|
373
|
-
```
|
374
|
-
|
375
|
-
### Exchange unbinding
|
376
|
-
|
377
|
-
To unbind an exchange from another exchange call the **unbind** method, like so:
|
378
|
-
|
379
|
-
```Ruby
|
380
|
-
Rabbits::Exchanges::MyExchange.unbind(Rabbits::Exchanges::MyExchangeTwo, 'my.binding.key', arguments: {})
|
381
|
-
```
|
382
|
-
|
383
|
-
or
|
384
|
-
|
385
|
-
```Ruby
|
386
|
-
Rabbits::Exchanges::MyExchange.unbind('my.exchange.two', 'my.binding.key', arguments: {})
|
387
|
-
```
|
388
|
-
|
389
|
-
### Publishing to an exchange
|
390
|
-
|
391
|
-
To publish a message to an exchange call the **publish** method, like so:
|
392
|
-
|
393
|
-
```Ruby
|
394
|
-
Rabbits::Exchanges::MyExchange.publish('my message', 'my.routing.key', properties: {})
|
395
|
-
```
|
396
|
-
|
397
|
-
The **publish** method accepts several options, here's the method documentation:
|
398
|
-
|
399
|
-
```Ruby
|
400
|
-
# @param [String] body The message body, can be a string or either a byte array
|
401
|
-
# @param [String] routing_key The routing key to route the message to bounded queues
|
402
|
-
# @param [Hash] properties Request properties
|
403
|
-
# @option properties [String] :app_id Used to identify the app that generated the message
|
404
|
-
# @option properties [String] :content_encoding Content encoding of the body
|
405
|
-
# @option properties [String] :content_type Content type of the body
|
406
|
-
# @option properties [Integer] :correlation_id The correlation id, mostly used used for RPC communication
|
407
|
-
# @option properties [Integer] :delivery_mode 2 for persistent messages, all other values are for transient messages
|
408
|
-
# @option properties [Integer, String] :expiration Number of seconds the message will stay in the queue
|
409
|
-
# @option properties [Hash<String, Object>] :headers Custom headers
|
410
|
-
# @option properties [Boolean] :mandatory The message will be returned if the message can't be routed to a queue
|
411
|
-
# @option properties [String] :message_id Can be used to uniquely identify the message, e.g. for deduplication
|
412
|
-
# @option properties [Boolean] :persistent Same as delivery_mode: 2
|
413
|
-
# @option properties [Integer] :priority The message priority (between 0 and 255)
|
414
|
-
# @option properties [String] :reply_to Queue to reply RPC responses to
|
415
|
-
# @option properties [Date] :timestamp Often used for the time the message was originally generated
|
416
|
-
# @option properties [String] :type Can indicate what kind of message this is
|
417
|
-
# @option properties [String] :user_id Used to identify the user that published the message
|
418
|
-
#
|
419
|
-
# @return [Boolean] true if published, false otherwise
|
420
|
-
#
|
421
|
-
def publish(body, routing_key, **properties)
|
422
|
-
```
|
423
|
-
|
424
|
-
### Delete an exchange
|
425
|
-
|
426
|
-
To delete an exchange from RabbitMQ call the **delete** method, like so:
|
427
|
-
|
428
|
-
```Ruby
|
429
|
-
Rabbits::Exchanges::MyExchange.delete
|
430
|
-
```
|
431
|
-
|
432
|
-
## Logging
|
433
|
-
|
434
|
-
Queues and Exchanges have a built-in logger.
|
435
|
-
|
436
|
-
Each queue and each exchange will have its log file inside the `log` directory. The filename will match the queue/exchange name.
|
437
|
-
|
438
|
-
While [consuming messages from a queue](#subscribing-a-queue), logs will also get pushed to `STDOUT`.
|
439
|
-
|
440
|
-
## Usage tips
|
441
|
-
|
442
|
-
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.
|
443
|
-
|
444
|
-
```Bash
|
445
|
-
rails runner -e production "Rabbits::Queues::MyQueue.subscribe"
|
446
|
-
```
|
447
|
-
|
448
|
-
If you are running the queues in development mode, there could be some problems due to the Rails lazy loading. To solve this issue, you can add the following lines to `config/environments/development.rb`:
|
449
|
-
|
450
|
-
```Ruby
|
451
|
-
config.eager_load_paths += Dir["app/queues/**/*.rb"]
|
452
|
-
ActiveSupport::Reloader.to_prepare do
|
453
|
-
Dir["app/queues/**/*.rb"].each { |f| require_dependency("#{Dir.pwd}/#{f}") }
|
454
|
-
end
|
455
|
-
```
|
31
|
+
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).
|
456
32
|
|
457
33
|
## Contributing
|
458
34
|
|
459
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
460
|
-
|
461
|
-
## Credits
|
462
|
-
|
463
|
-
The gem is based on the amazing RabbitMQ client by [cloudamqp](https://github.com/cloudamqp/amqp-client.rb).
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/queues-rabbit.
|
464
36
|
|
465
37
|
## License
|
466
38
|
|
data/lib/queues/rabbit.rb
CHANGED
@@ -1,30 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require 'amqp-client'
|
5
|
-
require 'logger'
|
6
|
-
|
7
|
-
require_relative 'rabbit/client'
|
8
|
-
require_relative 'rabbit/exchange'
|
9
|
-
require_relative 'rabbit/logger'
|
10
|
-
require_relative 'rabbit/message'
|
11
|
-
require_relative 'rabbit/queue'
|
12
|
-
require_relative 'rabbit/schema'
|
13
|
-
require_relative 'rabbit/version'
|
3
|
+
require_relative "rabbit/version"
|
14
4
|
|
15
5
|
module Queues
|
16
6
|
module Rabbit
|
17
7
|
class Error < StandardError; end
|
18
|
-
|
19
|
-
class << self
|
20
|
-
attr_accessor :client, :logger, :log_level, :schema
|
21
|
-
|
22
|
-
def configure(schema_klass, host, log_level: ::Logger::INFO)
|
23
|
-
self.log_level = log_level
|
24
|
-
self.schema = schema_klass
|
25
|
-
schema.client = Queues::Rabbit::Client.new(host)
|
26
|
-
self
|
27
|
-
end
|
28
|
-
end
|
8
|
+
# Your code goes here...
|
29
9
|
end
|
30
10
|
end
|
metadata
CHANGED
@@ -1,45 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: queues-rabbit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.
|
4
|
+
version: 0.1.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lapo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
12
|
-
dependencies:
|
13
|
-
|
14
|
-
name: amqp-client
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: queues
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - '='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.1.0.beta
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - '='
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 0.1.0.beta
|
41
|
-
description: The gem allows you to integrate RabbitMQ into a Rails application in
|
42
|
-
a Ruby Style fashion.
|
11
|
+
date: 2022-02-25 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: ''
|
43
14
|
email:
|
44
15
|
- lapoelisacci@gmail.com
|
45
16
|
executables: []
|
@@ -50,21 +21,10 @@ files:
|
|
50
21
|
- ".rubocop.yml"
|
51
22
|
- CHANGELOG.md
|
52
23
|
- Gemfile
|
53
|
-
- Gemfile.lock
|
54
24
|
- LICENSE.txt
|
55
25
|
- README.md
|
56
26
|
- Rakefile
|
57
|
-
- lib/generators/queues_rabbit_generator.rb
|
58
|
-
- lib/generators/templates/exchange.rb
|
59
|
-
- lib/generators/templates/queue.rb
|
60
|
-
- lib/generators/templates/schema.rb
|
61
27
|
- lib/queues/rabbit.rb
|
62
|
-
- lib/queues/rabbit/client.rb
|
63
|
-
- lib/queues/rabbit/exchange.rb
|
64
|
-
- lib/queues/rabbit/logger.rb
|
65
|
-
- lib/queues/rabbit/message.rb
|
66
|
-
- lib/queues/rabbit/queue.rb
|
67
|
-
- lib/queues/rabbit/schema.rb
|
68
28
|
- lib/queues/rabbit/version.rb
|
69
29
|
- sig/queues/rabbit.rbs
|
70
30
|
homepage: https://github.com/LapoElisacci/queues.git
|
@@ -92,5 +52,5 @@ requirements: []
|
|
92
52
|
rubygems_version: 3.2.22
|
93
53
|
signing_key:
|
94
54
|
specification_version: 4
|
95
|
-
summary:
|
55
|
+
summary: RabbitMQ Driver for Rails Queues
|
96
56
|
test_files: []
|
data/Gemfile.lock
DELETED
@@ -1,201 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
queues-rabbit (0.1.0.pre)
|
5
|
-
amqp-client (~> 1)
|
6
|
-
queues (= 0.1.0.beta)
|
7
|
-
|
8
|
-
GEM
|
9
|
-
remote: https://rubygems.org/
|
10
|
-
specs:
|
11
|
-
actioncable (7.0.2.2)
|
12
|
-
actionpack (= 7.0.2.2)
|
13
|
-
activesupport (= 7.0.2.2)
|
14
|
-
nio4r (~> 2.0)
|
15
|
-
websocket-driver (>= 0.6.1)
|
16
|
-
actionmailbox (7.0.2.2)
|
17
|
-
actionpack (= 7.0.2.2)
|
18
|
-
activejob (= 7.0.2.2)
|
19
|
-
activerecord (= 7.0.2.2)
|
20
|
-
activestorage (= 7.0.2.2)
|
21
|
-
activesupport (= 7.0.2.2)
|
22
|
-
mail (>= 2.7.1)
|
23
|
-
net-imap
|
24
|
-
net-pop
|
25
|
-
net-smtp
|
26
|
-
actionmailer (7.0.2.2)
|
27
|
-
actionpack (= 7.0.2.2)
|
28
|
-
actionview (= 7.0.2.2)
|
29
|
-
activejob (= 7.0.2.2)
|
30
|
-
activesupport (= 7.0.2.2)
|
31
|
-
mail (~> 2.5, >= 2.5.4)
|
32
|
-
net-imap
|
33
|
-
net-pop
|
34
|
-
net-smtp
|
35
|
-
rails-dom-testing (~> 2.0)
|
36
|
-
actionpack (7.0.2.2)
|
37
|
-
actionview (= 7.0.2.2)
|
38
|
-
activesupport (= 7.0.2.2)
|
39
|
-
rack (~> 2.0, >= 2.2.0)
|
40
|
-
rack-test (>= 0.6.3)
|
41
|
-
rails-dom-testing (~> 2.0)
|
42
|
-
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
43
|
-
actiontext (7.0.2.2)
|
44
|
-
actionpack (= 7.0.2.2)
|
45
|
-
activerecord (= 7.0.2.2)
|
46
|
-
activestorage (= 7.0.2.2)
|
47
|
-
activesupport (= 7.0.2.2)
|
48
|
-
globalid (>= 0.6.0)
|
49
|
-
nokogiri (>= 1.8.5)
|
50
|
-
actionview (7.0.2.2)
|
51
|
-
activesupport (= 7.0.2.2)
|
52
|
-
builder (~> 3.1)
|
53
|
-
erubi (~> 1.4)
|
54
|
-
rails-dom-testing (~> 2.0)
|
55
|
-
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
56
|
-
activejob (7.0.2.2)
|
57
|
-
activesupport (= 7.0.2.2)
|
58
|
-
globalid (>= 0.3.6)
|
59
|
-
activemodel (7.0.2.2)
|
60
|
-
activesupport (= 7.0.2.2)
|
61
|
-
activerecord (7.0.2.2)
|
62
|
-
activemodel (= 7.0.2.2)
|
63
|
-
activesupport (= 7.0.2.2)
|
64
|
-
activestorage (7.0.2.2)
|
65
|
-
actionpack (= 7.0.2.2)
|
66
|
-
activejob (= 7.0.2.2)
|
67
|
-
activerecord (= 7.0.2.2)
|
68
|
-
activesupport (= 7.0.2.2)
|
69
|
-
marcel (~> 1.0)
|
70
|
-
mini_mime (>= 1.1.0)
|
71
|
-
activesupport (7.0.2.2)
|
72
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
73
|
-
i18n (>= 1.6, < 2)
|
74
|
-
minitest (>= 5.1)
|
75
|
-
tzinfo (~> 2.0)
|
76
|
-
amqp-client (1.1.4)
|
77
|
-
ast (2.4.2)
|
78
|
-
builder (3.2.4)
|
79
|
-
concurrent-ruby (1.1.9)
|
80
|
-
crass (1.0.6)
|
81
|
-
diff-lcs (1.5.0)
|
82
|
-
digest (3.1.0)
|
83
|
-
erubi (1.10.0)
|
84
|
-
globalid (1.0.0)
|
85
|
-
activesupport (>= 5.0)
|
86
|
-
i18n (1.10.0)
|
87
|
-
concurrent-ruby (~> 1.0)
|
88
|
-
io-wait (0.2.1)
|
89
|
-
loofah (2.14.0)
|
90
|
-
crass (~> 1.0.2)
|
91
|
-
nokogiri (>= 1.5.9)
|
92
|
-
mail (2.7.1)
|
93
|
-
mini_mime (>= 0.1.1)
|
94
|
-
marcel (1.0.2)
|
95
|
-
method_source (1.0.0)
|
96
|
-
mini_mime (1.1.2)
|
97
|
-
minitest (5.15.0)
|
98
|
-
net-imap (0.2.3)
|
99
|
-
digest
|
100
|
-
net-protocol
|
101
|
-
strscan
|
102
|
-
net-pop (0.1.1)
|
103
|
-
digest
|
104
|
-
net-protocol
|
105
|
-
timeout
|
106
|
-
net-protocol (0.1.2)
|
107
|
-
io-wait
|
108
|
-
timeout
|
109
|
-
net-smtp (0.3.1)
|
110
|
-
digest
|
111
|
-
net-protocol
|
112
|
-
timeout
|
113
|
-
nio4r (2.5.8)
|
114
|
-
nokogiri (1.13.3-x86_64-darwin)
|
115
|
-
racc (~> 1.4)
|
116
|
-
parallel (1.21.0)
|
117
|
-
parser (3.1.1.0)
|
118
|
-
ast (~> 2.4.1)
|
119
|
-
queues (0.1.0.beta)
|
120
|
-
rails (>= 5)
|
121
|
-
racc (1.6.0)
|
122
|
-
rack (2.2.3)
|
123
|
-
rack-test (1.1.0)
|
124
|
-
rack (>= 1.0, < 3)
|
125
|
-
rails (7.0.2.2)
|
126
|
-
actioncable (= 7.0.2.2)
|
127
|
-
actionmailbox (= 7.0.2.2)
|
128
|
-
actionmailer (= 7.0.2.2)
|
129
|
-
actionpack (= 7.0.2.2)
|
130
|
-
actiontext (= 7.0.2.2)
|
131
|
-
actionview (= 7.0.2.2)
|
132
|
-
activejob (= 7.0.2.2)
|
133
|
-
activemodel (= 7.0.2.2)
|
134
|
-
activerecord (= 7.0.2.2)
|
135
|
-
activestorage (= 7.0.2.2)
|
136
|
-
activesupport (= 7.0.2.2)
|
137
|
-
bundler (>= 1.15.0)
|
138
|
-
railties (= 7.0.2.2)
|
139
|
-
rails-dom-testing (2.0.3)
|
140
|
-
activesupport (>= 4.2.0)
|
141
|
-
nokogiri (>= 1.6)
|
142
|
-
rails-html-sanitizer (1.4.2)
|
143
|
-
loofah (~> 2.3)
|
144
|
-
railties (7.0.2.2)
|
145
|
-
actionpack (= 7.0.2.2)
|
146
|
-
activesupport (= 7.0.2.2)
|
147
|
-
method_source
|
148
|
-
rake (>= 12.2)
|
149
|
-
thor (~> 1.0)
|
150
|
-
zeitwerk (~> 2.5)
|
151
|
-
rainbow (3.1.1)
|
152
|
-
rake (13.0.6)
|
153
|
-
regexp_parser (2.2.1)
|
154
|
-
rexml (3.2.5)
|
155
|
-
rspec (3.11.0)
|
156
|
-
rspec-core (~> 3.11.0)
|
157
|
-
rspec-expectations (~> 3.11.0)
|
158
|
-
rspec-mocks (~> 3.11.0)
|
159
|
-
rspec-core (3.11.0)
|
160
|
-
rspec-support (~> 3.11.0)
|
161
|
-
rspec-expectations (3.11.0)
|
162
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
163
|
-
rspec-support (~> 3.11.0)
|
164
|
-
rspec-mocks (3.11.0)
|
165
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
166
|
-
rspec-support (~> 3.11.0)
|
167
|
-
rspec-support (3.11.0)
|
168
|
-
rubocop (1.25.1)
|
169
|
-
parallel (~> 1.10)
|
170
|
-
parser (>= 3.1.0.0)
|
171
|
-
rainbow (>= 2.2.2, < 4.0)
|
172
|
-
regexp_parser (>= 1.8, < 3.0)
|
173
|
-
rexml
|
174
|
-
rubocop-ast (>= 1.15.1, < 2.0)
|
175
|
-
ruby-progressbar (~> 1.7)
|
176
|
-
unicode-display_width (>= 1.4.0, < 3.0)
|
177
|
-
rubocop-ast (1.16.0)
|
178
|
-
parser (>= 3.1.1.0)
|
179
|
-
ruby-progressbar (1.11.0)
|
180
|
-
strscan (3.0.1)
|
181
|
-
thor (1.2.1)
|
182
|
-
timeout (0.2.0)
|
183
|
-
tzinfo (2.0.4)
|
184
|
-
concurrent-ruby (~> 1.0)
|
185
|
-
unicode-display_width (2.1.0)
|
186
|
-
websocket-driver (0.7.5)
|
187
|
-
websocket-extensions (>= 0.1.0)
|
188
|
-
websocket-extensions (0.1.5)
|
189
|
-
zeitwerk (2.5.4)
|
190
|
-
|
191
|
-
PLATFORMS
|
192
|
-
x86_64-darwin-20
|
193
|
-
|
194
|
-
DEPENDENCIES
|
195
|
-
queues-rabbit!
|
196
|
-
rake (~> 13.0)
|
197
|
-
rspec (~> 3.0)
|
198
|
-
rubocop (~> 1.21)
|
199
|
-
|
200
|
-
BUNDLED WITH
|
201
|
-
2.3.7
|
@@ -1,26 +0,0 @@
|
|
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
|
@@ -1,13 +0,0 @@
|
|
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
|
@@ -1,30 +0,0 @@
|
|
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 (it must be >= batch_size if batch_subscribe is called)
|
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
|
-
|
20
|
-
def batch_consume(messages)
|
21
|
-
puts "Received #{messages.size} messages"
|
22
|
-
# do something with the messages
|
23
|
-
messages.each(&:ack)
|
24
|
-
puts "Acked #{messages.size} messages"
|
25
|
-
rescue
|
26
|
-
messages.each { |msg| msg.reject(requeue: false) }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/queues/rabbit/client.rb
DELETED
@@ -1,135 +0,0 @@
|
|
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
|
-
#
|
10
|
-
# Bind an Exchange to another Exchange
|
11
|
-
#
|
12
|
-
# @param [String] exchange Exchange name
|
13
|
-
# @param [String] binding_key Exchange binding key
|
14
|
-
# @param [Hash] arguments Message headers to match on (only relevant for header exchanges)
|
15
|
-
#
|
16
|
-
# @return [Boolean] True if bounded, false otherwise
|
17
|
-
#
|
18
|
-
def bind(exchange, binding_key, arguments: {})
|
19
|
-
exchange = exchange < Queues::Rabbit::Exchange ? exchange.name : exchange
|
20
|
-
exchange_instance.bind(exchange, binding_key, arguments: arguments)
|
21
|
-
true
|
22
|
-
rescue Exception => e
|
23
|
-
logger.error_with_report "Unable to bind '#{name}' to '#{exchange}' with key '#{binding_key}' and arguments: '#{arguments}': #{e.message}."
|
24
|
-
false
|
25
|
-
end
|
26
|
-
|
27
|
-
#
|
28
|
-
# Delete an Exchange from RabbitMQ
|
29
|
-
#
|
30
|
-
# @return [Boolean] True if deleted, false otherwise
|
31
|
-
#
|
32
|
-
def delete
|
33
|
-
exchange_instance.delete
|
34
|
-
true
|
35
|
-
rescue Exception => e
|
36
|
-
logger.error_with_report "Unable to delete #{name}: #{e.message}."
|
37
|
-
false
|
38
|
-
end
|
39
|
-
|
40
|
-
#
|
41
|
-
# Declare an Exchange
|
42
|
-
#
|
43
|
-
# @param [String] name Exchange name
|
44
|
-
# @param [String] type Exchange type
|
45
|
-
# @param [Hash] arguments Exchange custom arguments
|
46
|
-
# @param [Boolean] auto_delete If true, the exchange will be deleted when the last queue/exchange gets unbounded.
|
47
|
-
# @param [Boolean] durable If true, the exchange will persist between broker restarts, also a required for persistent messages.
|
48
|
-
# @param [Boolean] internal If true, the messages can't be pushed directly to the exchange.
|
49
|
-
#
|
50
|
-
# @return [Queues::Rabbit::Exchange] Exchange class
|
51
|
-
#
|
52
|
-
def exchange(name, type, arguments: {}, auto_delete: false, durable: true, internal: false)
|
53
|
-
self.arguments = arguments
|
54
|
-
self.auto_delete = auto_delete
|
55
|
-
self.name = name
|
56
|
-
self.durable = durable
|
57
|
-
self.internal = internal
|
58
|
-
self.name = name
|
59
|
-
self.type = type
|
60
|
-
self
|
61
|
-
end
|
62
|
-
|
63
|
-
#
|
64
|
-
# Publish a message to the Exchange
|
65
|
-
#
|
66
|
-
# @param [String] body The message body, can be a string or either a byte array
|
67
|
-
# @param [String] routing_key The routing key to route the message to bounded queues
|
68
|
-
# @param [Hash] properties Request properties
|
69
|
-
# @option properties [String] :app_id Used to identify the app that generated the message
|
70
|
-
# @option properties [String] :content_encoding Content encoding of the body
|
71
|
-
# @option properties [String] :content_type Content type of the body
|
72
|
-
# @option properties [Integer] :correlation_id The correlation id, mostly used used for RPC communication
|
73
|
-
# @option properties [Integer] :delivery_mode 2 for persistent messages, all other values are for transient messages
|
74
|
-
# @option properties [Integer, String] :expiration Number of seconds the message will stay in the queue
|
75
|
-
# @option properties [Hash<String, Object>] :headers Custom headers
|
76
|
-
# @option properties [Boolean] :mandatory The message will be returned if the message can't be routed to a queue
|
77
|
-
# @option properties [String] :message_id Can be used to uniquely identify the message, e.g. for deduplication
|
78
|
-
# @option properties [Boolean] :persistent Same as delivery_mode: 2
|
79
|
-
# @option properties [Integer] :priority The message priority (between 0 and 255)
|
80
|
-
# @option properties [String] :reply_to Queue to reply RPC responses to
|
81
|
-
# @option properties [Date] :timestamp Often used for the time the message was originally generated
|
82
|
-
# @option properties [String] :type Can indicate what kind of message this is
|
83
|
-
# @option properties [String] :user_id Used to identify the user that published the message
|
84
|
-
#
|
85
|
-
# @return [Boolean] true if published, false otherwise
|
86
|
-
#
|
87
|
-
def publish(body, routing_key, **properties)
|
88
|
-
exchange_instance.publish(body, name, routing_key, **properties)
|
89
|
-
true
|
90
|
-
rescue Exception => e
|
91
|
-
logger.error_with_report "Unable to publish to #{name}: #{e.message}."
|
92
|
-
false
|
93
|
-
end
|
94
|
-
|
95
|
-
#
|
96
|
-
# Unbind the Exchange from another Exchange
|
97
|
-
#
|
98
|
-
# @param [String] exchange The exchange name to unbind
|
99
|
-
# @param [String] binding_key The exchange binding key
|
100
|
-
# @param [Hash] arguments Message headers to match on (only relevant for header exchanges)
|
101
|
-
#
|
102
|
-
# @return [Boolean] True if unbound, false otherwise
|
103
|
-
#
|
104
|
-
def unbind(exchange, binding_key, arguments: {})
|
105
|
-
exchange = exchange < Queues::Rabbit::Exchange ? exchange.name : exchange
|
106
|
-
exchange_instance.unbind(exchange, binding_key, arguments: arguments)
|
107
|
-
true
|
108
|
-
rescue Exception => e
|
109
|
-
logger.error_with_report "Unable to unbind '#{name}' to '#{exchange}' with key '#{binding_key}' and arguments: '#{arguments}': #{e.message}."
|
110
|
-
false
|
111
|
-
end
|
112
|
-
|
113
|
-
private
|
114
|
-
|
115
|
-
#
|
116
|
-
# Return the Exchange instance
|
117
|
-
#
|
118
|
-
# @return [AMQP::Client::Exchange] Exchange instance
|
119
|
-
#
|
120
|
-
def exchange_instance
|
121
|
-
@@exchange_instance ||= schema.client_instance.exchange(name, type, arguments: arguments, auto_delete: auto_delete, durable: durable, internal: internal)
|
122
|
-
end
|
123
|
-
|
124
|
-
#
|
125
|
-
# Return the logger instance
|
126
|
-
#
|
127
|
-
# @return [Queues::Rabbit::Logger] Logger instance
|
128
|
-
#
|
129
|
-
def logger
|
130
|
-
@@logger ||= Queues::Rabbit::Logger.new(name, Queues::Rabbit.log_level)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
data/lib/queues/rabbit/logger.rb
DELETED
@@ -1,36 +0,0 @@
|
|
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
|
-
#
|
16
|
-
# Log an error with attached report string.
|
17
|
-
#
|
18
|
-
# @param [String] message Message to log
|
19
|
-
#
|
20
|
-
def error_with_report(message)
|
21
|
-
@logger.error { message }
|
22
|
-
@logger.error { 'Please report to https://github.com/LapoElisacci/queues-rabbit if needed.' }
|
23
|
-
end
|
24
|
-
|
25
|
-
#
|
26
|
-
# Log the passed message to STDOUT
|
27
|
-
#
|
28
|
-
# @param [String] message Message to log
|
29
|
-
# @param [Symbol] level Log level
|
30
|
-
#
|
31
|
-
def stdout(message, level = :info)
|
32
|
-
@std.send(level, message)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Queues
|
4
|
-
module Rabbit
|
5
|
-
#
|
6
|
-
# AMQP::Client::Message wrapper class
|
7
|
-
#
|
8
|
-
class Message < AMQP::Client::Message
|
9
|
-
def initialize(message)
|
10
|
-
message.instance_variables.each do |variable|
|
11
|
-
instance_variable_set(variable, message.instance_variable_get(variable))
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
data/lib/queues/rabbit/queue.rb
DELETED
@@ -1,222 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Queues
|
4
|
-
module Rabbit
|
5
|
-
class Queue
|
6
|
-
class << self
|
7
|
-
attr_accessor :arguments, :auto_delete, :durable, :name, :no_ack, :prefetch, :schema
|
8
|
-
|
9
|
-
#
|
10
|
-
# Bind a Queue to an Exchange
|
11
|
-
#
|
12
|
-
# @param [String] exchange Exchange name
|
13
|
-
# @param [String] binding_key Exchange binding key
|
14
|
-
# @param [Hash] arguments Message headers to match on (only relevant for header exchanges)
|
15
|
-
#
|
16
|
-
# @return [Boolean] True if bounded, false otherwise
|
17
|
-
#
|
18
|
-
def bind(exchange, binding_key, arguments: {})
|
19
|
-
exchange = exchange < Queues::Rabbit::Exchange ? exchange.name : exchange
|
20
|
-
queue_instance.bind(exchange, binding_key, arguments: arguments)
|
21
|
-
true
|
22
|
-
rescue Exception => e
|
23
|
-
logger.error_with_report "Unable to bind '#{name}' to '#{exchange}' with key '#{binding_key}' and arguments: '#{arguments}': #{e.message}."
|
24
|
-
false
|
25
|
-
end
|
26
|
-
|
27
|
-
def consume(_message)
|
28
|
-
raise NoMethodError.new("Method #{__method__} must be defined to subscribe a queue!")
|
29
|
-
end
|
30
|
-
|
31
|
-
def batch_consume(_messages)
|
32
|
-
raise NoMethodError.new("Method #{__method__} must be defined to batch-subscribe a queue!")
|
33
|
-
end
|
34
|
-
|
35
|
-
#
|
36
|
-
# Delete a Queue from RabbitMQ
|
37
|
-
#
|
38
|
-
# @return [Boolean] True if delete, false otherwise
|
39
|
-
#
|
40
|
-
def delete
|
41
|
-
queue_instance.delete
|
42
|
-
true
|
43
|
-
rescue Exception => e
|
44
|
-
logger.error_with_report "Unable to delete #{name}: #{e.message}."
|
45
|
-
false
|
46
|
-
end
|
47
|
-
|
48
|
-
#
|
49
|
-
# Declare a Queue
|
50
|
-
#
|
51
|
-
# @param [String] name Queue name
|
52
|
-
# @param [Hash] arguments Custom arguments, such as queue-ttl etc.
|
53
|
-
# @param [Boolean] auto_ack When false messages have to be manually acknowledged (or rejected)
|
54
|
-
# @param [Boolean] auto_delete If true, the queue will be deleted when the last consumer stops consuming.
|
55
|
-
# @param [Boolean] durable If true, the queue will survive broker restarts, messages in the queue will only survive if they are published as persistent.
|
56
|
-
# @param [Integer] prefetch Specify how many messages to prefetch
|
57
|
-
#
|
58
|
-
# @return [Queues::Rabbit::Queue] Queue class
|
59
|
-
#
|
60
|
-
def queue(name, arguments: {}, auto_ack: true, auto_delete: false, durable: true, prefetch: 1)
|
61
|
-
self.arguments = arguments
|
62
|
-
self.auto_delete = auto_delete
|
63
|
-
self.durable = durable
|
64
|
-
self.name = name
|
65
|
-
self.no_ack = auto_ack
|
66
|
-
self.prefetch = prefetch
|
67
|
-
self
|
68
|
-
end
|
69
|
-
|
70
|
-
#
|
71
|
-
# Publish a message to the Queue
|
72
|
-
#
|
73
|
-
# @param [String] body The message body, can be a string or either a byte array
|
74
|
-
# @param [Hash] properties Request properties
|
75
|
-
# @option properties [String] :app_id Used to identify the app that generated the message
|
76
|
-
# @option properties [String] :content_encoding Content encoding of the body
|
77
|
-
# @option properties [String] :content_type Content type of the body
|
78
|
-
# @option properties [Integer] :correlation_id The correlation id, mostly used used for RPC communication
|
79
|
-
# @option properties [Integer] :delivery_mode 2 for persistent messages, all other values are for transient messages
|
80
|
-
# @option properties [Integer, String] :expiration Number of seconds the message will stay in the queue
|
81
|
-
# @option properties [Hash<String, Object>] :headers Custom headers
|
82
|
-
# @option properties [Boolean] :mandatory The message will be returned if the message can't be routed to a queue
|
83
|
-
# @option properties [String] :message_id Can be used to uniquely identify the message, e.g. for deduplication
|
84
|
-
# @option properties [Boolean] :persistent Same as delivery_mode: 2
|
85
|
-
# @option properties [Integer] :priority The message priority (between 0 and 255)
|
86
|
-
# @option properties [String] :reply_to Queue to reply RPC responses to
|
87
|
-
# @option properties [Date] :timestamp Often used for the time the message was originally generated
|
88
|
-
# @option properties [String] :type Can indicate what kind of message this is
|
89
|
-
# @option properties [String] :user_id Used to identify the user that published the message
|
90
|
-
#
|
91
|
-
# @return [Boolean] True if published, false otherwise
|
92
|
-
#
|
93
|
-
def publish(body, **properties)
|
94
|
-
queue_instance.publish(body, **properties)
|
95
|
-
true
|
96
|
-
rescue Exception => e
|
97
|
-
logger.error_with_report "Unable to publish to #{name}: #{e.message}."
|
98
|
-
false
|
99
|
-
end
|
100
|
-
|
101
|
-
#
|
102
|
-
# Purge / Empty a queue from RabbitMQ
|
103
|
-
#
|
104
|
-
# @return [Boolean] True if purged, false otherwise
|
105
|
-
#
|
106
|
-
def purge
|
107
|
-
queue_instance.purge
|
108
|
-
true
|
109
|
-
rescue Exception => e
|
110
|
-
logger.error_with_report "Unable to purge #{name}: #{e.message}."
|
111
|
-
false
|
112
|
-
end
|
113
|
-
|
114
|
-
#
|
115
|
-
# Subscribe to a Queue
|
116
|
-
#
|
117
|
-
def subscribe
|
118
|
-
logger.info { "Subscribing to queue #{name}" }
|
119
|
-
consumer = new
|
120
|
-
queue_instance.subscribe(no_ack: no_ack, prefetch: prefetch) do |message|
|
121
|
-
consumer.consume(Queues::Rabbit::Message.new(message))
|
122
|
-
rescue Exception => e
|
123
|
-
logger.error { e.message }
|
124
|
-
logger.stdout e.message, :error
|
125
|
-
end
|
126
|
-
|
127
|
-
loop do
|
128
|
-
logger.stdout "Connection to #{name} alive."
|
129
|
-
sleep 10
|
130
|
-
end
|
131
|
-
rescue Exception => e
|
132
|
-
logger.error_with_report "Unable to connect to #{name}: #{e.message}."
|
133
|
-
false
|
134
|
-
end
|
135
|
-
|
136
|
-
#
|
137
|
-
# Subscribe to the queue with a batch reading.
|
138
|
-
# This method will block.
|
139
|
-
#
|
140
|
-
# @param [Integer] batch_size Batch size
|
141
|
-
# @param [ActiveSupport::Duration] batch_timeout Batch timeout, that the time interval in which the batch will be emptied even if not full.
|
142
|
-
#
|
143
|
-
# @return [FalseClass] if errors
|
144
|
-
#
|
145
|
-
def batch_subscribe(batch_size:, batch_timeout:)
|
146
|
-
raise StandardError.new('Batch size must be a positive integer') if batch_size.to_i <= 0
|
147
|
-
raise StandardError.new("Batch size must be less or equal than prefetch: got batch_size=#{batch_size} and prefetch=#{prefetch}") if batch_size > prefetch
|
148
|
-
|
149
|
-
logger.info "Subscribing to queue #{name} with a batch size #{batch_size}"
|
150
|
-
consumer = new
|
151
|
-
batch = []
|
152
|
-
# Batched subscribe must be performed only by one thread
|
153
|
-
# Auto-acking is done manually, otherwise batching is not possible
|
154
|
-
queue_instance.subscribe(worker_threads: 1, no_ack: false, prefetch: prefetch) do |message|
|
155
|
-
if message.properties.type == 'timeout'
|
156
|
-
message.ack # Remove the timeout message from the queue
|
157
|
-
min_batch_size = 0
|
158
|
-
else
|
159
|
-
batch << Queues::Rabbit::Message.new(message)
|
160
|
-
min_batch_size = batch_size
|
161
|
-
end
|
162
|
-
if batch.size > 0 && batch.size >= min_batch_size
|
163
|
-
batch.each(&:ack) if no_ack
|
164
|
-
consumer.batch_consume(batch)
|
165
|
-
batch = []
|
166
|
-
end
|
167
|
-
rescue Exception => e
|
168
|
-
logger.error { e.message }
|
169
|
-
logger.stdout e.message, :error
|
170
|
-
end
|
171
|
-
|
172
|
-
loop do
|
173
|
-
logger.stdout "Connection to #{name} alive."
|
174
|
-
sleep batch_timeout
|
175
|
-
queue_instance.publish('', type: 'timeout', persistent: false, espiration: 3.seconds)
|
176
|
-
end
|
177
|
-
rescue Exception => e
|
178
|
-
logger.error_with_report "Unable to connect to #{name}: #{e.message}."
|
179
|
-
false
|
180
|
-
end
|
181
|
-
|
182
|
-
#
|
183
|
-
# Unbind a Queue from an Exchange
|
184
|
-
#
|
185
|
-
# @param [String] exchange Exchange name
|
186
|
-
# @param [String] binding_key Exchange binding key
|
187
|
-
# @param [Hash] arguments Message headers to match on (only relevant for header exchanges)
|
188
|
-
#
|
189
|
-
# @return [Boolean] True if unbounded, false otherwise.
|
190
|
-
#
|
191
|
-
def unbind(exchange, binding_key, arguments: {})
|
192
|
-
exchange = exchange < Queues::Rabbit::Exchange ? exchange.name : exchange
|
193
|
-
queue_instance.unbind(exhange, binding_key, arguments: arguments)
|
194
|
-
true
|
195
|
-
rescue Exception => e
|
196
|
-
logger.error_with_report "Unable to unbind '#{name}' to '#{exchange}' with key '#{binding_key}' and arguments: '#{arguments}': #{e.message}."
|
197
|
-
false
|
198
|
-
end
|
199
|
-
|
200
|
-
private
|
201
|
-
|
202
|
-
#
|
203
|
-
# Return the logger instance
|
204
|
-
#
|
205
|
-
# @return [Queues::Rabbit::Logger] Logger instance
|
206
|
-
#
|
207
|
-
def logger
|
208
|
-
@@logger ||= Queues::Rabbit::Logger.new(name, Queues::Rabbit.log_level)
|
209
|
-
end
|
210
|
-
|
211
|
-
#
|
212
|
-
# Return the Queue instance
|
213
|
-
#
|
214
|
-
# @return [AMQP::Client::Client] Queue instance
|
215
|
-
#
|
216
|
-
def queue_instance
|
217
|
-
@@queue_instance ||= schema.client_instance.queue(name, arguments: arguments, auto_delete: auto_delete, durable: durable)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
data/lib/queues/rabbit/schema.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Queues
|
4
|
-
module Rabbit
|
5
|
-
class Schema
|
6
|
-
class << self
|
7
|
-
attr_accessor :client, :exchanges, :queues
|
8
|
-
|
9
|
-
#
|
10
|
-
# Return the client instance
|
11
|
-
#
|
12
|
-
# @return [AMQP::Client] Client instance
|
13
|
-
#
|
14
|
-
def client_instance
|
15
|
-
@@client_instance ||= client.start
|
16
|
-
end
|
17
|
-
|
18
|
-
#
|
19
|
-
# Register an Exchange
|
20
|
-
#
|
21
|
-
# @param [Queues::Rabbit::Exchange] klass Exchange class to register
|
22
|
-
#
|
23
|
-
def exchange(klass)
|
24
|
-
self.exchanges ||= []
|
25
|
-
self.exchanges << klass
|
26
|
-
klass.schema = self
|
27
|
-
end
|
28
|
-
|
29
|
-
#
|
30
|
-
# Register a Queue
|
31
|
-
#
|
32
|
-
# @param [Queues::Rabbit::Queue] klass Queue class to register
|
33
|
-
#
|
34
|
-
def queue(klass)
|
35
|
-
self.queues ||= []
|
36
|
-
self.queues << klass
|
37
|
-
klass.schema = self
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|