bug_bunny 1.0.1 → 2.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/README.md +154 -34
- data/Rakefile +5 -1
- data/lib/bug_bunny/config.rb +2 -2
- data/lib/bug_bunny/controller.rb +80 -7
- data/lib/bug_bunny/exception.rb +14 -66
- data/lib/bug_bunny/publisher.rb +115 -0
- data/lib/bug_bunny/rabbit.rb +283 -83
- data/lib/bug_bunny/resource.rb +226 -0
- data/lib/bug_bunny/version.rb +1 -1
- data/lib/bug_bunny.rb +7 -16
- metadata +8 -13
- data/Gemfile +0 -8
- data/lib/bug_bunny/adapter.rb +0 -347
- data/lib/bug_bunny/helpers.rb +0 -36
- data/lib/bug_bunny/message.rb +0 -161
- data/lib/bug_bunny/queue.rb +0 -23
- data/lib/bug_bunny/railtie.rb +0 -124
- data/lib/bug_bunny/response.rb +0 -15
- data/lib/bug_bunny/security.rb +0 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 074005f6739a5a8486230e47edbce60b9719f5e15f35d9ab3ed95d91eaf28a47
|
|
4
|
+
data.tar.gz: 39f1d8afb65be6ff2b86e0461c16c93e0ff6ae6cbe629668ba8e6601fe898e80
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 88e99f4d71b1bb78599cf7a1750218cf5fde2e9ccb010c1aa671d1ba5e1ffe011a9bc70c39fe284b150d6fb497827e94766a82085a3758308990e57eb0f0b5da
|
|
7
|
+
data.tar.gz: 66acaa871a7f5adabf4135c3b84216f71072be0f9bc7f76c4e42247dde064709596c78b88fed32c9bd24bc47a6ba737d54bc7c3396509f4dae61f06c69d026fd
|
data/README.md
CHANGED
|
@@ -1,63 +1,183 @@
|
|
|
1
1
|
# BugBunny
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Configuration
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
config/initializers/bug_bunny.rb
|
|
7
|
+
BugBunny.configure do |config|
|
|
8
|
+
config.host = 'Host'
|
|
9
|
+
config.username = 'Username'
|
|
10
|
+
config.password = 'Password'
|
|
11
|
+
config.vhost = '/'
|
|
12
|
+
config.logger = Rails.logger
|
|
13
|
+
config.automatically_recover = false
|
|
14
|
+
config.network_recovery_interval = 5
|
|
15
|
+
config.connection_timeout = 10
|
|
16
|
+
config.read_timeout = 30
|
|
17
|
+
config.write_timeout = 30
|
|
18
|
+
config.heartbeat = 15
|
|
19
|
+
config.continuation_timeout = 15_000
|
|
20
|
+
end
|
|
21
|
+
```
|
|
4
22
|
|
|
5
|
-
|
|
23
|
+
## Publish
|
|
24
|
+
|
|
25
|
+
### Rutas
|
|
6
26
|
|
|
7
27
|
```
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
28
|
+
# config/rabbit_rest.yml
|
|
29
|
+
default: &default
|
|
30
|
+
healt_check:
|
|
31
|
+
up: 'healt_check/up'
|
|
32
|
+
manager:
|
|
33
|
+
services:
|
|
34
|
+
index: 'services/index'
|
|
35
|
+
create: 'services/create'
|
|
36
|
+
show: 'services/%<id>s/show'
|
|
37
|
+
update: 'services/%<id>s/update'
|
|
38
|
+
destroy: 'services/%<id>s/destroy'
|
|
39
|
+
swarm:
|
|
40
|
+
info: 'swarm/info'
|
|
41
|
+
version: 'swarm/version'
|
|
42
|
+
swarm: 'swarm/swarm'
|
|
43
|
+
tasks:
|
|
44
|
+
index: 'tasks/index'
|
|
45
|
+
|
|
46
|
+
development:
|
|
47
|
+
<<: *default
|
|
48
|
+
|
|
49
|
+
test:
|
|
50
|
+
<<: *default
|
|
51
|
+
|
|
52
|
+
production:
|
|
53
|
+
<<: *default
|
|
13
54
|
|
|
14
|
-
|
|
55
|
+
```
|
|
15
56
|
|
|
16
|
-
|
|
57
|
+
### Configuration
|
|
17
58
|
|
|
18
|
-
|
|
59
|
+
```ruby
|
|
60
|
+
# config/initializers/bug_bunny.rb
|
|
61
|
+
BUG_BUNNY_ENDPOINTS = Rails.application.config_for(:rabbit_rest)
|
|
19
62
|
|
|
20
|
-
|
|
21
|
-
|
|
63
|
+
BUNNY_POOL = ConnectionPool.new(size: RABBIT_MAX_THREADS) do
|
|
64
|
+
BugBunny::Rabbit.create_connection(host: RABBIT_HOST, username: RABBIT_USER, password: RABBIT_PASS, vhost: RABBIT_VIRTUAL_HOST)
|
|
22
65
|
end
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Publisher
|
|
69
|
+
|
|
70
|
+
Creamos cualquier clase que herede de `BugBunny::Publisher`, luego definimos metodos de clase y dentro de cada una de ella su implementacion
|
|
23
71
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
72
|
+
1. Mensajes sincronicos
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
class Rabbit::Publisher::Manager < BugBunny::Publisher
|
|
76
|
+
ROUTING_KEY = :manager
|
|
77
|
+
ROUTES = BUG_BUNNY_ENDPOINTS[:manager][:swarm]
|
|
78
|
+
|
|
79
|
+
def self.info(exchange:, message: nil)
|
|
80
|
+
obj = new(pool: NEW_BUNNY_POOL, exchange_name: exchange, action: self::ROUTES[:info], message: message)
|
|
81
|
+
obj.publish_and_consume!
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.version(exchange:, message: nil)
|
|
85
|
+
obj = new(pool: NEW_BUNNY_POOL, exchange_name: exchange, action: self::ROUTES[:version], message: message)
|
|
86
|
+
obj.publish_and_consume!
|
|
33
87
|
end
|
|
34
88
|
end
|
|
35
89
|
```
|
|
36
90
|
|
|
91
|
+
2. Mensajes Asincronicos
|
|
37
92
|
|
|
93
|
+
```
|
|
94
|
+
class Rabbit::Publisher::Manager < BugBunny::Publisher
|
|
95
|
+
ROUTING_KEY = :manager
|
|
96
|
+
ROUTES = BUG_BUNNY_ENDPOINTS[:manager][:swarm]
|
|
38
97
|
|
|
39
|
-
|
|
98
|
+
def self.info(exchange:, message: nil)
|
|
99
|
+
obj = new(pool: NEW_BUNNY_POOL, exchange_name: exchange, action: self::ROUTES[:info], message: message)
|
|
100
|
+
obj.publish!
|
|
101
|
+
end
|
|
40
102
|
|
|
41
|
-
|
|
103
|
+
def self.version(exchange:, message: nil)
|
|
104
|
+
obj = new(pool: NEW_BUNNY_POOL, exchange_name: exchange, action: self::ROUTES[:version], message: message)
|
|
105
|
+
obj.publish!
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
```
|
|
42
109
|
|
|
43
|
-
|
|
110
|
+
3. Attributes del objeto BugBunny::Publisher
|
|
111
|
+
|
|
112
|
+
- content_type
|
|
113
|
+
- content_encoding
|
|
114
|
+
- correlation_id
|
|
115
|
+
- reply_to
|
|
116
|
+
- message_id
|
|
117
|
+
- timestamp
|
|
118
|
+
- priority
|
|
119
|
+
- expiration
|
|
120
|
+
- user_id
|
|
121
|
+
- app_id
|
|
122
|
+
- action
|
|
123
|
+
- aguments
|
|
124
|
+
- cluster_id
|
|
125
|
+
- persistent
|
|
126
|
+
- expiration
|
|
127
|
+
|
|
128
|
+
## Consumer
|
|
44
129
|
|
|
45
|
-
|
|
130
|
+
```
|
|
131
|
+
class Rabbit::Controllers::Application < BugBunny::Controller
|
|
132
|
+
end
|
|
46
133
|
|
|
47
|
-
|
|
134
|
+
class Rabbit::Controllers::Swarm < Rabbit::Controllers::Application
|
|
135
|
+
def info
|
|
136
|
+
render status: :ok, json: Api::Docker.info
|
|
137
|
+
end
|
|
48
138
|
|
|
49
|
-
|
|
139
|
+
def version
|
|
140
|
+
render status: :ok, json: Api::Docker.version
|
|
141
|
+
end
|
|
50
142
|
|
|
51
|
-
|
|
143
|
+
def swarm
|
|
144
|
+
render status: :ok, json: Api::Docker.swarm
|
|
145
|
+
end
|
|
146
|
+
end
|
|
52
147
|
|
|
53
|
-
|
|
148
|
+
```
|
|
54
149
|
|
|
55
|
-
##
|
|
150
|
+
## Resource
|
|
151
|
+
Solo para recursos que se adaptan al crud de rails estoy utilizando automaticamente la logica de los publicadores. Los atributos solo se ponen si son necesarios, si no la dejas vacia y actua igual que active resource.
|
|
56
152
|
|
|
57
|
-
|
|
153
|
+
```
|
|
154
|
+
class Manager::Application < BugBunny::Resource
|
|
155
|
+
self.resource_path = 'rabbit/publisher/manager'
|
|
156
|
+
|
|
157
|
+
attribute :id # 'ID'
|
|
158
|
+
attribute :version # 'Version'
|
|
159
|
+
attribute :created_at # 'CreatedAt'
|
|
160
|
+
attribute :update_at # 'UpdatedAt'
|
|
161
|
+
attribute :spec # 'Spec'
|
|
162
|
+
end
|
|
58
163
|
|
|
59
|
-
|
|
164
|
+
class Manager::Service < Manager::Application
|
|
165
|
+
attribute :endpoint # 'Endpoint'
|
|
166
|
+
end
|
|
60
167
|
|
|
61
|
-
|
|
168
|
+
```
|
|
62
169
|
|
|
63
|
-
|
|
170
|
+
## Exceptions
|
|
171
|
+
- Error General:
|
|
172
|
+
- `BugBunny::Error` hereda de `::StandardError` (Captura cualquier error de la gema.)
|
|
173
|
+
- Error de Publicadores:
|
|
174
|
+
- `BugBunny::PublishError` hereda de `BugBunny::Error` (Para fallos de envío o conexión.)
|
|
175
|
+
- Error de Respuestas:
|
|
176
|
+
- `BugBunny::ResponseError::Base` hereda de `BugBunny::Error` (Captura todos los errores de respuesta).
|
|
177
|
+
- Errores Específicos de Respuesta:
|
|
178
|
+
- `BugBunny::ResponseError::BadRequest`
|
|
179
|
+
- `BugBunny::ResponseError::NotFound`
|
|
180
|
+
- `BugBunny::ResponseError::NotAcceptable`
|
|
181
|
+
- `BugBunny::ResponseError::RequestTimeout`
|
|
182
|
+
- `BugBunny::ResponseError::UnprocessableEntity`: En este el error viene el error details a lo rails.
|
|
183
|
+
- `BugBunny::ResponseError::InternalServerError`
|
data/Rakefile
CHANGED
data/lib/bug_bunny/config.rb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
module BugBunny
|
|
2
2
|
class Config
|
|
3
3
|
# getter y setter para cada propiedad.
|
|
4
|
-
attr_accessor :
|
|
4
|
+
attr_accessor :host, :username, :password, :vhost, :logger, :automatically_recover, :network_recovery_interval, :connection_timeout, :read_timeout, :write_timeout, :heartbeat, :continuation_timeout
|
|
5
5
|
|
|
6
6
|
# Método para generar la URL de conexión
|
|
7
7
|
def url
|
|
8
|
-
"amqp://#{
|
|
8
|
+
"amqp://#{username}:#{password}@#{host}/#{vhost}"
|
|
9
9
|
end
|
|
10
10
|
end
|
|
11
11
|
end
|
data/lib/bug_bunny/controller.rb
CHANGED
|
@@ -1,16 +1,89 @@
|
|
|
1
1
|
module BugBunny
|
|
2
2
|
class Controller
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
include ActiveModel::Model
|
|
4
|
+
include ActiveModel::Attributes
|
|
5
|
+
|
|
6
|
+
attribute :headers
|
|
7
|
+
attribute :params
|
|
8
|
+
attribute :raw_string
|
|
9
|
+
|
|
10
|
+
attr_reader :rendered_response
|
|
11
|
+
|
|
12
|
+
def self.before_actions
|
|
13
|
+
# Nota el uso de '@' en lugar de '@@'
|
|
14
|
+
@before_actions ||= Hash.new { |hash, key| hash[key] = [] }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.before_action(method_name, **options)
|
|
18
|
+
actions = options.delete(:only) || []
|
|
19
|
+
|
|
20
|
+
if actions.empty?
|
|
21
|
+
before_actions[:_all_actions] << method_name
|
|
22
|
+
else
|
|
23
|
+
Array(actions).each do |action|
|
|
24
|
+
before_actions[action.to_sym] << method_name
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def _run_before_actions
|
|
30
|
+
current_action = headers[:action].to_sym
|
|
31
|
+
|
|
32
|
+
callbacks = self.class.before_actions[:_all_actions] + self.class.before_actions[current_action]
|
|
33
|
+
|
|
34
|
+
callbacks.each do |method_name|
|
|
35
|
+
send(method_name) if respond_to?(method_name, true)
|
|
36
|
+
return false if @rendered_response
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def render(status:, json: nil)
|
|
43
|
+
@rendered_response = self.class.render(status: status, json: json)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def safe_parse_body(body)
|
|
47
|
+
self.params ||= {}
|
|
48
|
+
|
|
49
|
+
return if body.blank?
|
|
50
|
+
|
|
51
|
+
case headers[:content_type]
|
|
52
|
+
when 'application/json', 'application/x-www-form-urlencoded'
|
|
53
|
+
if body.instance_of?(Hash)
|
|
54
|
+
params.merge!(body.deep_symbolize_keys)
|
|
55
|
+
else # es string
|
|
56
|
+
params.merge!(ActiveSupport::JSON.decode(body).deep_symbolize_keys)
|
|
57
|
+
end
|
|
58
|
+
when 'text/plain'
|
|
59
|
+
self.raw_string = body
|
|
60
|
+
end
|
|
5
61
|
end
|
|
6
62
|
|
|
7
|
-
def self.
|
|
8
|
-
|
|
63
|
+
def self.status_code_number(code)
|
|
64
|
+
codes = Rack::Utils::SYMBOL_TO_STATUS_CODE
|
|
65
|
+
codes[:unprocessable_entity] = 422
|
|
66
|
+
code = codes[code.to_sym] if codes.key?(code.to_sym)
|
|
67
|
+
code
|
|
9
68
|
end
|
|
10
69
|
|
|
11
|
-
def self.
|
|
12
|
-
|
|
13
|
-
|
|
70
|
+
def self.render(status:, json: nil)
|
|
71
|
+
status_number = status_code_number(status)
|
|
72
|
+
{ status: status_number, body: json }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.call(headers:, body: {})
|
|
76
|
+
controller = new(headers: headers)
|
|
77
|
+
controller.safe_parse_body(body)
|
|
78
|
+
controller.params[:id] = headers[:id] if headers.key?(:id)
|
|
79
|
+
controller.params.with_indifferent_access
|
|
80
|
+
return controller.rendered_response unless controller._run_before_actions
|
|
81
|
+
|
|
82
|
+
controller.send(controller.headers[:action])
|
|
83
|
+
rescue NoMethodError => e # action controller no exist
|
|
84
|
+
raise e
|
|
85
|
+
rescue StandardError => e
|
|
86
|
+
render status: :internal_server_error, json: e.message
|
|
14
87
|
end
|
|
15
88
|
end
|
|
16
89
|
end
|
data/lib/bug_bunny/exception.rb
CHANGED
|
@@ -1,69 +1,17 @@
|
|
|
1
1
|
module BugBunny
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
class
|
|
16
|
-
def to_s
|
|
17
|
-
:invalid_signature
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
class GatewayError < StandardError
|
|
22
|
-
def to_s
|
|
23
|
-
:gateway_error
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
class UltraCriticError < StandardError
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
class ComunicationRabbitError < StandardError
|
|
31
|
-
attr_accessor :backtrace
|
|
32
|
-
|
|
33
|
-
def initialize(msg, backtrace)
|
|
34
|
-
@backtrace = backtrace
|
|
35
|
-
super(msg)
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
class WithOutConsumer < StandardError
|
|
40
|
-
attr_accessor :backtrace
|
|
41
|
-
|
|
42
|
-
def initialize(msg, backtrace)
|
|
43
|
-
@backtrace = backtrace
|
|
44
|
-
super(msg)
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
class RetryWithoutError < StandardError
|
|
49
|
-
def to_s
|
|
50
|
-
"retry_sidekiq_without_error"
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def backtrace
|
|
54
|
-
[]
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
ServiceClasses = [
|
|
59
|
-
Exception::NeedSignature,
|
|
60
|
-
Exception::InvalidSignature,
|
|
61
|
-
Exception::ServiceError,
|
|
62
|
-
Exception::GatewayError,
|
|
63
|
-
Exception::RetryWithoutError
|
|
64
|
-
]
|
|
65
|
-
|
|
66
|
-
# Exceptions from ActiveRecord::StatementInvalid
|
|
67
|
-
PG_EXCEPTIONS_TO_EXIT = %w[PG::ConnectionBad PG::UnableToSend].freeze
|
|
2
|
+
# Clase base para TODOS los errores de la gema BugBunny.
|
|
3
|
+
# Ayuda a atrapar cualquier error de la gema con un solo 'rescue BugBunny::Error'.
|
|
4
|
+
class Error < ::StandardError; end
|
|
5
|
+
class PublishError < Error; end
|
|
6
|
+
|
|
7
|
+
module ResponseError
|
|
8
|
+
class Base < Error; end
|
|
9
|
+
|
|
10
|
+
class BadRequest < Base; end # HTTP 400
|
|
11
|
+
class NotFound < Base; end # HTTP 404
|
|
12
|
+
class NotAcceptable < Base; end # HTTP 406
|
|
13
|
+
class RequestTimeout < Base; end # HTTP 408
|
|
14
|
+
class UnprocessableEntity < Base; end # HTTP 422
|
|
15
|
+
class InternalServerError < Base; end # HTTP 500
|
|
68
16
|
end
|
|
69
17
|
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# content_type:
|
|
2
|
+
# Propósito: Indica el formato de codificación del cuerpo del mensaje (ej. application/json, text/plain, application/xml).
|
|
3
|
+
# Uso Recomendado: dice a tu código qué lógica de deserialización aplicar. Si es application/json, usas JSON.parse.
|
|
4
|
+
|
|
5
|
+
# content_encoding:
|
|
6
|
+
# Propósito: Indica cómo se comprimió o codificó el cuerpo del mensaje (ej. gzip, utf-8).
|
|
7
|
+
# Uso Recomendado: Si envías cuerpos grandes, puedes comprimirlos (ej. con Gzip) para ahorrar ancho de banda y usar este campo para que el consumidor sepa cómo descomprimirlos antes de usar el content_type.
|
|
8
|
+
|
|
9
|
+
# correlation_id:
|
|
10
|
+
# Propósito: Un identificador único que se usa para correlacionar una respuesta con una petición previa.
|
|
11
|
+
# Uso Recomendado: Es indispensable en el patrón Remote Procedure Call (RPC). Si un productor envía una petición, copia este ID a la respuesta. Cuando el productor recibe la respuesta, usa este ID para saber a qué petición original corresponde.
|
|
12
|
+
|
|
13
|
+
# reply_to:
|
|
14
|
+
# Propósito: Especifica el nombre de la cola a la que el consumidor debe enviar la respuesta.
|
|
15
|
+
# Uso Recomendado: También clave en RPC. El productor especifica aquí su cola de respuesta temporal o exclusiva. El consumidor toma el mensaje, procesa, y publica el resultado en la cola indicada en reply_to.
|
|
16
|
+
|
|
17
|
+
# message_id:
|
|
18
|
+
# Propósito: Un identificador único para el mensaje en sí.
|
|
19
|
+
# Uso Recomendado: Ayuda a prevenir el procesamiento duplicado si un sistema de consumo cae y se recupera. El consumidor puede almacenar los message_id ya procesados.
|
|
20
|
+
|
|
21
|
+
# timestamp:
|
|
22
|
+
# Propósito: Indica la hora y fecha en que el mensaje fue publicado por el productor.
|
|
23
|
+
# Uso Recomendado: Útil para auditoría, diagnóstico y seguimiento de la latencia del sistema.
|
|
24
|
+
|
|
25
|
+
# priority:
|
|
26
|
+
# Propósito: Un valor entero que indica la prioridad relativa del mensaje (de 0 a 9, siendo 9 la más alta).
|
|
27
|
+
# Uso Recomendado: Solo funciona si la cola receptora está configurada como una Cola de Prioridades. Si lo está, RabbitMQ dará preferencia a los mensajes con mayor prioridad.
|
|
28
|
+
|
|
29
|
+
# expiration:
|
|
30
|
+
# Propósito: Especifica el tiempo de vida (TTL - Time To Live) del mensaje en la cola, en milisegundos.
|
|
31
|
+
# Uso Recomendado: Si el mensaje caduca antes de ser consumido, RabbitMQ lo descartará o lo moverá a la Dead Letter Queue (DLQ). Es vital para mensajes sensibles al tiempo (ej. tokens o alertas).
|
|
32
|
+
|
|
33
|
+
# user_id y app_id:
|
|
34
|
+
# Propósito: Identificadores que especifican qué usuario y qué aplicación generaron el mensaje.
|
|
35
|
+
# Uso Recomendado: Auditoría y seguridad. El broker (RabbitMQ) puede verificar que el user_id coincida con el usuario de la conexión AMQP utilizada para publicar.
|
|
36
|
+
|
|
37
|
+
# type:
|
|
38
|
+
# Propósito: Un identificador de aplicación para describir el "tipo" o "clase" de la carga útil del mensaje.
|
|
39
|
+
# Uso Recomendado: Usado a menudo para el enrutamiento interno dentro de una aplicación consumidora, similar al header Action que usas. Por ejemplo, en lugar de usar headers[:action], podrías usar properties[:type].
|
|
40
|
+
|
|
41
|
+
# cluster_id:
|
|
42
|
+
# Propósito: Obsoleto en AMQP 0-9-1 y no debe ser utilizado.
|
|
43
|
+
|
|
44
|
+
# persistent:
|
|
45
|
+
# Un valor booleano (true o false). Cuando es true, le dice a RabbitMQ que el mensaje debe persistir en el disco. Si el servidor de RabbitMQ se reinicia, el mensaje no se perderá.
|
|
46
|
+
|
|
47
|
+
# expiration:
|
|
48
|
+
# El tiempo de vida del mensaje en milisegundos. Después de este tiempo, RabbitMQ lo descartará automáticamente si no ha sido consumido.
|
|
49
|
+
module BugBunny
|
|
50
|
+
class Publisher
|
|
51
|
+
include ActiveModel::Model
|
|
52
|
+
include ActiveModel::Attributes
|
|
53
|
+
|
|
54
|
+
attribute :message
|
|
55
|
+
attribute :pool
|
|
56
|
+
attribute :routing_key, :string
|
|
57
|
+
attribute :persistent, :boolean, default: false
|
|
58
|
+
attribute :content_type, :string, default: "application/json"
|
|
59
|
+
attribute :content_encoding, :string, default: "utf-8"
|
|
60
|
+
attribute :correlation_id, :string
|
|
61
|
+
attribute :reply_to, :string
|
|
62
|
+
attribute :app_id, :string
|
|
63
|
+
attribute :headers, default: {}
|
|
64
|
+
attribute :message_id, :string, default: -> { SecureRandom.uuid }
|
|
65
|
+
attribute :timestamp, :datetime, default: -> { Time.zone.now.utc.to_i }
|
|
66
|
+
attribute :expiration, :integer, default: -> { 1.day.in_milliseconds } #ms
|
|
67
|
+
attribute :exchange_name, :string
|
|
68
|
+
attribute :exchange_type, :string, default: 'direct'
|
|
69
|
+
attr_accessor :type
|
|
70
|
+
|
|
71
|
+
attribute :action, :string
|
|
72
|
+
attribute :arguments, default: {}
|
|
73
|
+
|
|
74
|
+
def publish!
|
|
75
|
+
pool.with do |conn|
|
|
76
|
+
app = Rabbit.new(connection: conn)
|
|
77
|
+
app.build_exchange(name: exchange_name, type: exchange_type)
|
|
78
|
+
app.publish!(message, publish_opts)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def publish_and_consume!
|
|
83
|
+
pool.with do |conn|
|
|
84
|
+
app = Rabbit.new(connection: conn)
|
|
85
|
+
app.build_exchange(name: exchange_name, type: exchange_type)
|
|
86
|
+
app.publish_and_consume!(message, publish_opts)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def publish_opts
|
|
91
|
+
{ routing_key: routing_key,
|
|
92
|
+
type: type,
|
|
93
|
+
persistent: persistent,
|
|
94
|
+
content_type: content_type,
|
|
95
|
+
content_encoding: content_encoding,
|
|
96
|
+
correlation_id: correlation_id,
|
|
97
|
+
reply_to: reply_to,
|
|
98
|
+
app_id: app_id,
|
|
99
|
+
headers: headers,
|
|
100
|
+
timestamp: timestamp,
|
|
101
|
+
expiration: expiration }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def type
|
|
105
|
+
return if action.blank?
|
|
106
|
+
|
|
107
|
+
self.type = format(action, arguments)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def initialize(attrs = {})
|
|
111
|
+
super(attrs)
|
|
112
|
+
self.routing_key ||= self.class::ROUTING_KEY
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|