queues-rabbit 0.1.0.beta.1 → 0.1.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
![](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)
|
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
|