rabbitmq_client 0.0.0.pre → 0.0.1
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/.gitignore +3 -1
- data/.reek.yml +21 -0
- data/.travis.yml +12 -1
- data/README.md +129 -17
- data/bin/setup +4 -0
- data/lib/rabbitmq_client/callback.rb +47 -0
- data/lib/rabbitmq_client/exchange.rb +25 -0
- data/lib/rabbitmq_client/exchange_registry.rb +33 -0
- data/lib/rabbitmq_client/json_formatter.rb +29 -0
- data/lib/rabbitmq_client/json_log_subscriber.rb +90 -0
- data/lib/rabbitmq_client/lifecycle.rb +53 -0
- data/lib/rabbitmq_client/log_subscriber_base.rb +16 -0
- data/lib/rabbitmq_client/logger_builder.rb +35 -0
- data/lib/rabbitmq_client/message_publisher.rb +57 -0
- data/lib/rabbitmq_client/plain_log_subscriber.rb +64 -0
- data/lib/rabbitmq_client/plugin.rb +31 -0
- data/lib/rabbitmq_client/publisher.rb +79 -0
- data/lib/rabbitmq_client/tags_filter.rb +16 -0
- data/lib/rabbitmq_client/text_formatter.rb +42 -0
- data/lib/rabbitmq_client/version.rb +2 -1
- data/lib/rabbitmq_client.rb +99 -2
- data/rabbitmq_client.gemspec +1 -0
- data/script/travis.sh +2 -0
- data/spec/callback_spec.rb +31 -0
- data/spec/exchange_registry_spec.rb +32 -0
- data/spec/json_formatter_spec.rb +43 -0
- data/spec/json_log_subscriber_spec.rb +145 -0
- data/spec/lifecycle_spec.rb +78 -0
- data/spec/plain_log_subscriber_spec.rb +115 -0
- data/spec/plugin_spec.rb +12 -0
- data/spec/publisher_spec.rb +150 -0
- data/spec/rabbitmq_client_spec.rb +83 -0
- data/spec/support/dummy_rabbitmq_client_plugin.rb +13 -0
- data/spec/tags_filter_spec.rb +37 -0
- data/spec/text_formatter_spec.rb +45 -0
- metadata +57 -5
- data/Gemfile.lock +0 -156
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2b060865b600b3377cbb16799ecdc82fedbd874b8b9f158c58a57604925c7b8
|
4
|
+
data.tar.gz: 211d0b536583982f7248a188daab96c77ec2a37765f840bdf85b4dfb9bf27930
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ca283805742bb671e6f43818ba3c9ad4f2ad8587f708c1d41fd472ccfaefa6e50f8d615feffeb4699a7a5f1b8957ebe5eda770f77229cab60a8283c066640b5
|
7
|
+
data.tar.gz: 5431a7e2bfe7a6ef70ab1bdcdb9e79069178b1071f09a481c656c431d7e7174291efbf4861d6e4ee35fc7cfc6d0d3620e1fff7a188b5d83a6bc3c3765cbb2224
|
data/.gitignore
CHANGED
data/.reek.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
---
|
2
|
+
detectors:
|
3
|
+
LongParameterList:
|
4
|
+
max_params: 5
|
5
|
+
TooManyStatements:
|
6
|
+
enabled: true
|
7
|
+
max_statements: 10
|
8
|
+
UncommunicativeVariableName:
|
9
|
+
accept:
|
10
|
+
- e
|
11
|
+
Attribute:
|
12
|
+
exclude:
|
13
|
+
- "RabbitmqClient::Plugin#callback_block"
|
14
|
+
UtilityFunction:
|
15
|
+
exclude:
|
16
|
+
- 'RabbitmqClient::Publisher#notify'
|
17
|
+
- 'LogSubscriberBase#logger'
|
18
|
+
- 'RabbitmqClient::JsonLogSubscriber'
|
19
|
+
FeatureEnvy:
|
20
|
+
exclude:
|
21
|
+
- 'RabbitmqClient::PlainLogSubscriber'
|
data/.travis.yml
CHANGED
@@ -6,12 +6,23 @@ branches:
|
|
6
6
|
|
7
7
|
rvm:
|
8
8
|
- 2.6.4
|
9
|
+
|
9
10
|
cache: bundler
|
10
11
|
bundler_args: "--jobs=3 --retry=3 --without production"
|
12
|
+
|
11
13
|
matrix:
|
12
14
|
fast_finish: true
|
15
|
+
|
13
16
|
script:
|
14
17
|
- sh script/travis.sh
|
18
|
+
|
19
|
+
notifications:
|
20
|
+
email: false # default notification method
|
21
|
+
slack:
|
22
|
+
if: branch = master
|
23
|
+
rooms:
|
24
|
+
secure: S5yfvL5slwkKqkIkUSEz3jcdMUGcaZ6tSlAL3h59p+Mlj40ezvKPvG3ZsSYw170+BQK0sxouxm1BpIGZ/aPu3ou6cK28eaaHrtS/CIVDM/6exobruWFAoidkjyyXyolzXAn/htAqOt3S21mCLfYDafUL2LeAnsheGf+TfPdKoBVwXzjn14RBsxW9qMOZ9rOgwxAikBtKELZyEr9MhBnLiJCSWFG/+sCvdYfpmAPvIlobZS65/943jbmUDMt0gu/AaW3De/97CaYF0rcxiiJVw/foDCJ5mX2UbzfGearxPzyF6F0ZjxGKHBEDQ+mqOE+cSPEKnkCc+YsBT4RhiyCWJupoEiCKbk3jy06n+8sT/PKvv+wDy4CUtYnqSXxSTVrUTWyqItxVEXUjK/+H8A7YosTC3FtVfYyZlVnmur0VitOCF9SKVUi+RtIrExGu5lI/Jvy6gUw6J2+tjWcDIoUuJ6iAKe84cRf1DUY4um3/M8QFI1QH21s9DT2bBfi5ombKeB4GkVqF7r26qbt18cDrYJwdUCVdRlYsXVyocHbrsBydBicUoTdbLLJlFI1PY4EiXNVlgVQKpnWdsodCu73xnLKxazqWX77gucXkvfIAKcu3br/onIU8IRGSPWKl7Bxo64/sNym4ZHFUYUS+ODFXUwiyykQcnyc25YnlgmHSDSo=
|
25
|
+
|
15
26
|
deploy:
|
16
27
|
provider: pages
|
17
28
|
skip-cleanup: true
|
@@ -19,4 +30,4 @@ deploy:
|
|
19
30
|
keep-history: true
|
20
31
|
verbose: true
|
21
32
|
on:
|
22
|
-
branch: master
|
33
|
+
branch: master
|
data/README.md
CHANGED
@@ -1,15 +1,44 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
```sh
|
3
|
+
____ _ _ _ _ __ __ ___ ____ _ _ _
|
4
|
+
| _ \ __ _| |__ | |__ (_) |_| \/ |/ _ \ / ___| (_) ___ _ __ | |_
|
5
|
+
| |_) / _` | '_ \| '_ \| | __| |\/| | | | | | | | | |/ _ \ '_ \| __|
|
6
|
+
| _ < (_| | |_) | |_) | | |_| | | | |_| | | |___| | | __/ | | | |_
|
7
|
+
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__\_\ \____|_|_|\___|_| |_|\__|
|
8
|
+
|
9
|
+
```
|
10
|
+
|
11
|
+
[](https://badge.fury.io/rb/rabbitmq_client)
|
12
|
+
[](http://opensource.org/licenses/MIT)
|
2
13
|
[](https://travis-ci.com/wshihadeh/rabbitmq_client)
|
3
14
|
[](https://depfu.com/github/wshihadeh/rabbitmq_client?project_id=9862)
|
4
|
-
[](https://wshihadeh.github.io/rabbitmq_client/
|
5
|
-
[](https://wshihadeh.github.io/rabbitmq_client/
|
15
|
+
[](https://wshihadeh.github.io/rabbitmq_client/coverage_info/index.html)
|
16
|
+
[](https://wshihadeh.github.io/rabbitmq_client/rubycritic/overview.html)
|
17
|
+
|
18
|
+
Simplifying RabbitMQ for Ruby apps!
|
19
|
+
|
20
|
+
RabbitMQ Client is a ruby client library for applications dealing with [RabbitMQ](https://www.rabbitmq.com/).
|
21
|
+
- It wraps common behaviors needed by publishers and subscribers in an easy and convenient API.
|
22
|
+
- It uses both `bunny` and `connection_pool` to manage RabbitMQ communications.
|
23
|
+
- It is extendable using plugins.
|
24
|
+
|
25
|
+
Why RabbitMQ Client? Why not `bunny` and `connection_pool` directly? Well, gems are just a clients. You still need to write a lot of code to manage proper subscribing and publishing of messages. You need to do error handling, passing request headers to RabbitMQ and maybe logging/instrumenting the message management process. Finally, you also need to consider how to deploy your app and how to start it.
|
26
|
+
|
27
|
+
With RabbitMQ Client by your side, all this becomes smooth and easy.
|
6
28
|
|
29
|
+
## Table of Contents
|
7
30
|
|
8
|
-
|
31
|
+
1. [Installation](#installation)
|
32
|
+
1. [Usage](#usage)
|
33
|
+
1. [Configurations](#usage-configuration)
|
34
|
+
1. [Publishing messages to RabbitMQ](#usage-publish-messages-to-rmq)
|
35
|
+
1. [Plugins](#plugins)
|
36
|
+
1. [Development and Testing](#development)
|
37
|
+
1. [Contributing](#contributing)
|
38
|
+
1. [License](#license)
|
9
39
|
|
10
|
-
TODO: Delete this and the text above, and describe your gem
|
11
40
|
|
12
|
-
## Installation
|
41
|
+
## <a name="installation"></a> Installation
|
13
42
|
|
14
43
|
Add this line to your application's Gemfile:
|
15
44
|
|
@@ -25,24 +54,107 @@ Or install it yourself as:
|
|
25
54
|
|
26
55
|
$ gem install rabbitmq_client
|
27
56
|
|
28
|
-
## Usage
|
57
|
+
## <a name="usage"></a> Usage
|
58
|
+
RabbitMQ Client can be used to publsih and subscribe RabbitMQ messages.
|
29
59
|
|
30
|
-
|
60
|
+
### <a name="usage-configuration"></a> Configurations
|
61
|
+
RabbitMQ Client support the following configurations
|
31
62
|
|
32
|
-
|
63
|
+
| Configuration | Description | Default Value |
|
64
|
+
|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------|
|
65
|
+
| rabbitmq_url | RabbitMQ server URL | amqp://guest:guest@127.0.0.1:5672 |
|
66
|
+
| logger_configs.logs_format | RabbitmqClient logs format.<br>values can be either json or plain | plain |
|
67
|
+
| logger_configs.logs_level | RabbitmqClient logs level.<br>values can be one of :debug, :info, :error | info |
|
68
|
+
| logger_configs.logs_filename | Logs file name, if nil STOUT will be used | nil |
|
69
|
+
| logger_configs.logger | Logger object, if nil STOUT logger will created | nil |
|
70
|
+
| session_params.heartbeat_publisher | Heartbeat interval for publisher sessions.<br>0 means no heartbeat | 0 |
|
71
|
+
| session_params.session_pool | Number of sessions with rabbitmq | 1 |
|
72
|
+
| plugins | Array of used plugins | [] |
|
73
|
+
| global_store | Global Store used to store tags and headers: <br>[RequestHeaderMiddleware](https://github.com/fidor/request_headers_middleware)<br>[RequestStore](https://github.com/steveklabnik/request_store) | nil |
|
74
|
+
| whitelist | List of whitelisted headers | ['x-request-id'.to_sym] |
|
33
75
|
|
34
|
-
|
76
|
+
#### Full Configuration Example
|
35
77
|
|
36
|
-
|
78
|
+
```ruby
|
79
|
+
RabbitmqClient.configure do |config|
|
80
|
+
config.rabbitmq_url = "${rabbitmq_url}"
|
81
|
+
config.logger_configs = {
|
82
|
+
logs_format: 'plain',
|
83
|
+
logs_level: :info,
|
84
|
+
logs_filename: nil,
|
85
|
+
logger: nil
|
86
|
+
}
|
87
|
+
config.session_params = {
|
88
|
+
heartbeat_publisher: 0,
|
89
|
+
session_pool: 1
|
90
|
+
}
|
91
|
+
config.plugins = []
|
92
|
+
config.global_store = RequestHeaderMiddleware
|
93
|
+
config.whitelist = ['x-request-id'.to_sym]
|
94
|
+
end
|
95
|
+
```
|
37
96
|
|
38
|
-
|
97
|
+
#### Append plungins or whitelist items
|
39
98
|
|
40
|
-
|
99
|
+
```ruby
|
100
|
+
RabbitmqClient.plugins << MYRabbitmqClientPlugin
|
101
|
+
RabbitmqClient.whitelist << :white_listed_header_key
|
102
|
+
```
|
41
103
|
|
42
|
-
|
104
|
+
### <a name="usage-publish-messages-to-rmq"></a> Publishing messages to RabbitMQ
|
105
|
+
- Publish messages using RabbitmqClient singleton publisher
|
43
106
|
|
44
|
-
|
107
|
+
```ruby
|
108
|
+
# RabbitmqClient.add_exchange(exchange, type, options)
|
109
|
+
RabbitmqClient.add_exchange('default.rabbitmq_client', :topic, {})
|
110
|
+
# RabbitmqClient.publish(payload, options)
|
111
|
+
RabbitmqClient.publish({id: 10, name: 'rabbitmq_client'}, { exchange_name: 'default.rabbitmq_client' })
|
112
|
+
```
|
113
|
+
|
114
|
+
- Create a publisher and use it
|
45
115
|
|
46
|
-
|
116
|
+
```ruby
|
117
|
+
config = {
|
118
|
+
rabbitmq_url: val,
|
119
|
+
exchange_registry: val,
|
120
|
+
session_params: { heartbeat_publisher: val }
|
121
|
+
}
|
47
122
|
|
48
|
-
|
123
|
+
publisher = RabbitmqClient::Publisher.new(config)
|
124
|
+
publisher.publish(payload, options)
|
125
|
+
```
|
126
|
+
|
127
|
+
## <a name="plugins"></a> Plugins
|
128
|
+
RabbitmqClient plugins are classes that define a callbacks that can be executed before or after events that occuers during RabbitmqClient lifecycle.
|
129
|
+
Current supprted lifecycle events are:
|
130
|
+
- publish: occure when publisgin a massage is triggered.
|
131
|
+
|
132
|
+
Here is an example where we define a plugin to add some headers to message options before publishing the message.
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
class MQTestPlugin < RabbitmqClient::Plugin
|
136
|
+
callbacks do |lifecycle|
|
137
|
+
lifecycle.before(:publish) do |_message, options|
|
138
|
+
options[:headers] = { test_key: 'test'}
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
RabbitmqClient.plugins << MQTestPlugin
|
143
|
+
```
|
144
|
+
## <a name="development"></a> Development and Testing
|
145
|
+
|
146
|
+
After checking out the repo:
|
147
|
+
* run `bin/setup` to install dependencies
|
148
|
+
* run `script/travis.sh` to run the tests.
|
149
|
+
|
150
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
151
|
+
|
152
|
+
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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
153
|
+
|
154
|
+
## <a name="contributing"></a> Contributing
|
155
|
+
|
156
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/wshihadeh/rabbitmq_client.
|
157
|
+
|
158
|
+
## <a name="license"></a> License
|
159
|
+
|
160
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/bin/setup
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RabbitmqClient
|
4
|
+
# Custom error thrown when an unsupported callback type is used
|
5
|
+
class InvalidCallback < RuntimeError
|
6
|
+
def initialize(name)
|
7
|
+
super("The Callback '#{name}' is an invalid callback and cannot be used")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Callback Object Store all plugins clallbacks
|
12
|
+
# Supported callback types are before and adter
|
13
|
+
class Callback
|
14
|
+
def initialize
|
15
|
+
@before = []
|
16
|
+
@after = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute(*args, &block)
|
20
|
+
execute_before_callbacks(*args)
|
21
|
+
result = block.call(*args)
|
22
|
+
execute_after_callbacks(*args)
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
def add(type, &callback)
|
27
|
+
case type
|
28
|
+
when :before
|
29
|
+
@before << callback
|
30
|
+
when :after
|
31
|
+
@after << callback
|
32
|
+
else
|
33
|
+
raise InvalidCallback, "Invalid callback type: #{type}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def execute_before_callbacks(*args)
|
40
|
+
@before.each { |callback| callback.call(*args) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def execute_after_callbacks(*args)
|
44
|
+
@after.each { |callback| callback.call(*args) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RabbitmqClient
|
4
|
+
# ExchangeRegistry is a store for all managed exchanges and their details
|
5
|
+
class Exchange
|
6
|
+
attr_reader :name, :type, :options
|
7
|
+
|
8
|
+
def initialize(name, type, options)
|
9
|
+
@name = name
|
10
|
+
@type = type
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def create(channel)
|
15
|
+
exhange_obj = Bunny::Exchange.new(channel, @type, @name,
|
16
|
+
@options)
|
17
|
+
ActiveSupport::Notifications.instrument(
|
18
|
+
'created_exhange.rabbitmq_client',
|
19
|
+
name: @name,
|
20
|
+
type: @type
|
21
|
+
)
|
22
|
+
exhange_obj
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'exchange'
|
4
|
+
|
5
|
+
module RabbitmqClient
|
6
|
+
# ExchangeRegistry is a store for all managed exchanges and their details
|
7
|
+
class ExchangeRegistry
|
8
|
+
# Custom Eroor thrown when trying to find unkown exchange
|
9
|
+
class ExchangeNotFound < StandardError
|
10
|
+
def initialize(name)
|
11
|
+
super("The Exchange '#{name}' cannot be found")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@exchanges = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(name, type, options = {})
|
20
|
+
@exchanges[name] = Exchange.new(name, type, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def find(name)
|
24
|
+
@exchanges.fetch(name) do
|
25
|
+
ActiveSupport::Notifications.instrument(
|
26
|
+
'exhange_not_found.rabbitmq_client',
|
27
|
+
name: name
|
28
|
+
)
|
29
|
+
raise ExchangeNotFound, name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module RabbitmqClient
|
6
|
+
# Formatter for json log messages
|
7
|
+
class JsonFormatter
|
8
|
+
TIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%6N '
|
9
|
+
def initialize
|
10
|
+
@json = {}
|
11
|
+
@msg = ''
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(severity, timestamp, progname, msg)
|
15
|
+
@json = build_new_json(msg)
|
16
|
+
@json = @json.merge(progname: progname.to_s, level: severity,
|
17
|
+
timestamp: timestamp.strftime(TIME_FORMAT))
|
18
|
+
@json = @json.reject { |_key, value| value.to_s.empty? }
|
19
|
+
|
20
|
+
@json.to_json + "\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_new_json(msg)
|
24
|
+
@msg = msg
|
25
|
+
@json = @msg.is_a?(Hash) ? @msg : { message: @msg.strip }
|
26
|
+
@json.merge(TagsFilter.tags || {})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'log_subscriber_base'
|
4
|
+
|
5
|
+
module RabbitmqClient
|
6
|
+
# Manage RabbitmqClient plain text logs
|
7
|
+
class JsonLogSubscriber < LogSubscriberBase
|
8
|
+
def publisher_created(event)
|
9
|
+
debug(action: 'publisher_created',
|
10
|
+
message: 'The RabbitmqClient publisher is created',
|
11
|
+
publisher_configs: event.payload)
|
12
|
+
end
|
13
|
+
|
14
|
+
def network_error(event)
|
15
|
+
payload = event.payload
|
16
|
+
error({ action: 'network_error',
|
17
|
+
message: 'Failed to publish a message',
|
18
|
+
error_message: payload.fetch(:error).message }.merge(
|
19
|
+
process_payload(payload)
|
20
|
+
))
|
21
|
+
end
|
22
|
+
|
23
|
+
def overriding_configs(event)
|
24
|
+
debug(action: 'overriding_configs',
|
25
|
+
message: 'Overriding publisher configs',
|
26
|
+
publisher_configs: event.payload)
|
27
|
+
end
|
28
|
+
|
29
|
+
def publishing_message(event)
|
30
|
+
debug({ action: 'publishing_message',
|
31
|
+
message: 'Publishing a new message' }.merge(
|
32
|
+
process_payload(event.payload)
|
33
|
+
))
|
34
|
+
end
|
35
|
+
|
36
|
+
def published_message(event)
|
37
|
+
info({ action: 'published_message',
|
38
|
+
message: 'Published a message' }.merge(
|
39
|
+
process_payload(event.payload)
|
40
|
+
))
|
41
|
+
end
|
42
|
+
|
43
|
+
def confirming_message(event)
|
44
|
+
debug({ action: 'confirming_message',
|
45
|
+
message: 'Confirming a message' }.merge(
|
46
|
+
process_payload(event.payload)
|
47
|
+
))
|
48
|
+
end
|
49
|
+
|
50
|
+
def message_confirmed(event)
|
51
|
+
debug({ action: 'message_confirmed',
|
52
|
+
message: 'Confirmed a message' }.merge(
|
53
|
+
process_payload(event.payload)
|
54
|
+
))
|
55
|
+
end
|
56
|
+
|
57
|
+
def exhange_not_found(event)
|
58
|
+
error(action: 'exhange_not_found',
|
59
|
+
message: 'Exhange Not Found',
|
60
|
+
exchange_name: event.payload.fetch(:name))
|
61
|
+
end
|
62
|
+
|
63
|
+
def created_exhange(event)
|
64
|
+
debug(action: 'created_exhange',
|
65
|
+
message: 'Exhange is created successfuly',
|
66
|
+
exchange_name: event.payload.fetch(:name))
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
%w[info debug warn error fatal unknown].each do |level|
|
72
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
73
|
+
def #{level}(progname = nil, &block)
|
74
|
+
logger.#{level} rabbitmq_client_event(progname, &block) if logger
|
75
|
+
end
|
76
|
+
METHOD
|
77
|
+
end
|
78
|
+
|
79
|
+
def rabbitmq_client_event(event)
|
80
|
+
{ source: 'rabbitmq_client' }.merge(event)
|
81
|
+
end
|
82
|
+
|
83
|
+
def process_payload(payload)
|
84
|
+
{
|
85
|
+
exchange_name: payload.fetch(:exchange, 'undefined'),
|
86
|
+
message_id: payload.fetch(:message_id, 'undefined')
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'callback'
|
4
|
+
|
5
|
+
module RabbitmqClient
|
6
|
+
# Lifecycle defines the rabbitmq_client lifecycle events,
|
7
|
+
# callbacks and manage the execution of these callbacks
|
8
|
+
class Lifecycle
|
9
|
+
EVENTS = {
|
10
|
+
publish: %i[message options]
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
attr_reader :callbacks
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@callbacks = EVENTS.keys.each_with_object({}) do |key, hash|
|
17
|
+
hash[key] = Callback.new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def before(event, &block)
|
22
|
+
add(:before, event, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def after(event, &block)
|
26
|
+
add(:after, event, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def run_callbacks(event, *args, &block)
|
30
|
+
missing_callback(event) unless @callbacks.key?(event)
|
31
|
+
event_obj = EVENTS[event]
|
32
|
+
event_size = event_obj.size
|
33
|
+
|
34
|
+
unless event_size == args.size
|
35
|
+
raise ArgumentError, "Callback #{event} expects\
|
36
|
+
#{event_size} parameter(s): #{event_obj.join(', ')}"
|
37
|
+
end
|
38
|
+
|
39
|
+
@callbacks[event].execute(*args, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def add(type, event, &block)
|
45
|
+
missing_callback(event) unless @callbacks.key?(event)
|
46
|
+
@callbacks[event].add(type, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
def missing_callback(event)
|
50
|
+
raise InvalidCallback, "Unknown callback event: #{event}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RabbitmqClient
|
4
|
+
# Log Subscriber base class
|
5
|
+
class LogSubscriberBase < ActiveSupport::LogSubscriber
|
6
|
+
class << self
|
7
|
+
def logger
|
8
|
+
@logger ||= RabbitmqClient.logger
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def logger
|
13
|
+
LogSubscriberBase.logger
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RabbitmqClient
|
4
|
+
# ExchangeRegistry is a store for all managed exchanges and their details
|
5
|
+
class LoggerBuilder
|
6
|
+
def initialize(config)
|
7
|
+
@logger = config[:logger].clone
|
8
|
+
@format = config[:logs_format]
|
9
|
+
@level = config[:logs_level].to_sym
|
10
|
+
@filename = config[:logs_filename]
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_logger
|
14
|
+
@logger ||= ::Logger.new(@filename || STDOUT)
|
15
|
+
@logger.level = @level
|
16
|
+
@logger.formatter = create_logger_formatter
|
17
|
+
log_subscriber.attach_to(:rabbitmq_client)
|
18
|
+
@logger
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def create_logger_formatter
|
24
|
+
json? ? JsonFormatter.new : TextFormatter.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def log_subscriber
|
28
|
+
json? ? JsonLogSubscriber : PlainLogSubscriber
|
29
|
+
end
|
30
|
+
|
31
|
+
def json?
|
32
|
+
__method__.to_s == "#{@format}?"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RabbitmqClient
|
4
|
+
# ExchangeRegistry is a store for all managed exchanges and their details
|
5
|
+
class MessagePublisher
|
6
|
+
# Custom error is thrown when rabbitmq do not confirm publishing an event
|
7
|
+
class ConfirmationFailed < StandardError
|
8
|
+
def initialize(exchange, nacked, unconfirmed)
|
9
|
+
msg = 'Message confirmation on the exchange ' \
|
10
|
+
"#{exchange} has failed (#{nacked}/#{unconfirmed})."
|
11
|
+
super(msg)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(data, exchange, channel, options)
|
16
|
+
@data = data.to_json
|
17
|
+
@exchange = exchange
|
18
|
+
@channel = channel
|
19
|
+
@options = { headers: {} }.merge(options)
|
20
|
+
@options[:headers][:tags] = TagsFilter.tags
|
21
|
+
end
|
22
|
+
|
23
|
+
def publish
|
24
|
+
exchange = @exchange.create(@channel)
|
25
|
+
|
26
|
+
notify('publishing_message')
|
27
|
+
exchange.publish(@data, **@options)
|
28
|
+
notify('published_message')
|
29
|
+
end
|
30
|
+
|
31
|
+
def wait_for_confirms
|
32
|
+
notify('confirming_message')
|
33
|
+
if @channel.wait_for_confirms
|
34
|
+
notify('message_confirmed')
|
35
|
+
return
|
36
|
+
end
|
37
|
+
raise ConfirmationFailed.new(@exchange.name, @channel.nacked_set,
|
38
|
+
@channel.unconfirmed_set)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def notify(event)
|
44
|
+
ActiveSupport::Notifications.instrument(
|
45
|
+
"#{event}.rabbitmq_client",
|
46
|
+
message_payload
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def message_payload
|
51
|
+
{
|
52
|
+
exchange: @exchange.name,
|
53
|
+
message_id: @options[:message_id]
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|