bug_bunny 3.0.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +166 -197
- data/lib/bug_bunny/config.rb +10 -0
- data/lib/bug_bunny/consumer.rb +68 -44
- data/lib/bug_bunny/controller.rb +131 -57
- data/lib/bug_bunny/producer.rb +10 -2
- data/lib/bug_bunny/resource.rb +133 -33
- data/lib/bug_bunny/version.rb +1 -1
- data/lib/bug_bunny.rb +1 -1
- metadata +21 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 42bf10dd1d3e749561b43b298e6dda00f9b6a76a40dce49103d1d094faa39948
|
|
4
|
+
data.tar.gz: 3088ecec60567a95972ed7abc7dff8f6dd9f5019ad6e0a19bb15dcae61e68bb3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ccf976738d355512f3effec2d84a94087c62b41b329516df4cb15ca99034385da216592a7b52acec6aa224708b7c5c272f17dde349a8d5fe88f3903e33ff1122
|
|
7
|
+
data.tar.gz: 60252a5667d1178b4ac9de5118dd21cfd5538c12c9f69360988f493ffea50c81e4efec2cc08f50570fc9e76c9a57d9bb08c1ef6d75aef4a6b25f995fc765b512
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.0.2] - 2026-02-12
|
|
4
|
+
|
|
5
|
+
### 🚀 Features
|
|
6
|
+
* **Automatic Parameter Wrapping:** `BugBunny::Resource` now automatically wraps the payload inside a root key derived from the model name (e.g., `Manager::Service` -> `{ service: { ... } }`). This mimics Rails form behavior and enables the use of `params.require(:service)` in controllers.
|
|
7
|
+
* Added `self.param_key = '...'` to `BugBunny::Resource` to allow custom root keys.
|
|
8
|
+
* **Declarative Error Handling:** Added Rails-like `rescue_from` DSL to `BugBunny::Controller`. You can now register exception handlers at the class level without overriding methods manually.
|
|
9
|
+
```ruby
|
|
10
|
+
rescue_from ActiveRecord::RecordNotFound do |e|
|
|
11
|
+
render status: :not_found, json: { error: e.message }
|
|
12
|
+
end
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 🐛 Bug Fixes
|
|
16
|
+
* **RPC Timeouts on Crash:** Fixed a critical issue where the Client would hang until timeout (`BugBunny::RequestTimeout`) if the Consumer crashed or the route was not found.
|
|
17
|
+
* The Consumer now catches `NameError` (Route not found) and returns a **501 Not Implemented**.
|
|
18
|
+
* The Consumer catches unhandled `StandardError` (App crash) and returns a **500 Internal Server Error**.
|
|
19
|
+
* Ensures a reply is ALWAYS sent to the caller, preventing blocking processes.
|
|
20
|
+
|
|
21
|
+
### 🛠 Improvements
|
|
22
|
+
* **Controller:** Refactored `BugBunny::Controller` to include a default safety net that catches unhandled errors and logs them properly before returning a 500 status.
|
|
23
|
+
|
|
3
24
|
## [3.0.1] - 2026-02-10
|
|
4
25
|
|
|
5
26
|
### 🚀 Features: RESTful Architecture
|
data/README.md
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**BugBunny** es un framework RPC para Ruby on Rails sobre **RabbitMQ**.
|
|
4
4
|
|
|
5
|
-
Su filosofía es **"Active Record over AMQP"**.
|
|
6
|
-
|
|
7
|
-
A diferencia de otros clientes de RabbitMQ, BugBunny viaja con **Verbos HTTP** (`GET`, `POST`, `PUT`, `DELETE`) inyectados en los headers AMQP. Esto permite construir una API semántica donde un **Router Inteligente** despacha los mensajes a controladores Rails estándar.
|
|
5
|
+
Su filosofía es **"Active Record over AMQP"**. Transforma la complejidad de la mensajería asíncrona en una arquitectura **RESTful simulada**. Los mensajes viajan con Verbos HTTP (`GET`, `POST`, `PUT`, `DELETE`) inyectados en los headers AMQP, permitiendo que un **Router Inteligente** despache las peticiones a controladores Rails estándar.
|
|
8
6
|
|
|
9
7
|
---
|
|
10
8
|
|
|
@@ -22,291 +20,262 @@ Ejecuta el bundle:
|
|
|
22
20
|
bundle install
|
|
23
21
|
```
|
|
24
22
|
|
|
25
|
-
|
|
23
|
+
Genera los archivos de configuración iniciales:
|
|
26
24
|
|
|
27
25
|
```bash
|
|
28
26
|
rails g bug_bunny:install
|
|
29
27
|
```
|
|
30
28
|
|
|
29
|
+
Esto creará:
|
|
30
|
+
1. `config/initializers/bug_bunny.rb`
|
|
31
|
+
2. `app/rabbit/controllers/`
|
|
32
|
+
|
|
31
33
|
---
|
|
32
34
|
|
|
33
35
|
## ⚙️ Configuración
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
### 1. Inicializador y Logging
|
|
38
|
+
|
|
39
|
+
BugBunny separa los logs de la aplicación (Requests) de los logs del driver (Heartbeats/Frames) para mantener la consola limpia.
|
|
36
40
|
|
|
37
41
|
```ruby
|
|
42
|
+
# config/initializers/bug_bunny.rb
|
|
43
|
+
|
|
38
44
|
BugBunny.configure do |config|
|
|
45
|
+
# --- Credenciales ---
|
|
39
46
|
config.host = ENV.fetch('RABBITMQ_HOST', 'localhost')
|
|
40
47
|
config.username = ENV.fetch('RABBITMQ_USER', 'guest')
|
|
41
48
|
config.password = ENV.fetch('RABBITMQ_PASS', 'guest')
|
|
42
49
|
config.vhost = ENV.fetch('RABBITMQ_VHOST', '/')
|
|
43
50
|
|
|
44
|
-
# Timeouts
|
|
45
|
-
config.rpc_timeout = 10
|
|
46
|
-
config.network_recovery_interval = 5
|
|
51
|
+
# --- Timeouts ---
|
|
52
|
+
config.rpc_timeout = 10 # Timeout para esperar respuesta (Síncrono)
|
|
53
|
+
config.network_recovery_interval = 5 # Segundos para reintentar conexión
|
|
54
|
+
|
|
55
|
+
# --- Logging (Niveles recomendados) ---
|
|
56
|
+
# Logger de BugBunny: Muestra tus requests (INFO)
|
|
57
|
+
config.logger = Logger.new(STDOUT)
|
|
58
|
+
config.logger.level = Logger::INFO
|
|
59
|
+
|
|
60
|
+
# Logger de Bunny (Driver): Silencia el ruido de bajo nivel (WARN)
|
|
61
|
+
config.bunny_logger = Logger.new(STDOUT)
|
|
62
|
+
config.bunny_logger.level = Logger::WARN
|
|
47
63
|
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 2. Connection Pool (Crítico) 🧵
|
|
67
|
+
|
|
68
|
+
Para entornos concurrentes como **Puma** o **Sidekiq**, es **obligatorio** definir un Pool de conexiones global. BugBunny no gestiona hilos automáticamente sin esta configuración.
|
|
48
69
|
|
|
49
|
-
|
|
50
|
-
#
|
|
51
|
-
|
|
70
|
+
```ruby
|
|
71
|
+
# config/initializers/bug_bunny.rb
|
|
72
|
+
|
|
73
|
+
# Define el pool global (ajusta el tamaño según tus hilos de Puma/Sidekiq)
|
|
52
74
|
BUG_BUNNY_POOL = ConnectionPool.new(size: ENV.fetch('RAILS_MAX_THREADS', 5).to_i, timeout: 5) do
|
|
53
75
|
BugBunny.create_connection
|
|
54
76
|
end
|
|
55
77
|
|
|
56
|
-
#
|
|
78
|
+
# Inyecta el pool a los recursos para que lo usen automáticamente
|
|
57
79
|
BugBunny::Resource.connection_pool = BUG_BUNNY_POOL
|
|
58
80
|
```
|
|
59
81
|
|
|
60
82
|
---
|
|
61
83
|
|
|
62
|
-
## 🚀 Modo Resource (ORM /
|
|
84
|
+
## 🚀 Modo Resource (ORM / Cliente)
|
|
63
85
|
|
|
64
|
-
Define modelos que actúan como proxies de recursos remotos. BugBunny
|
|
86
|
+
Define modelos que actúan como proxies de recursos remotos. BugBunny se encarga de serializar, "wrappear" parámetros y enviar el verbo correcto.
|
|
65
87
|
|
|
66
88
|
### Definición del Modelo
|
|
67
89
|
|
|
68
90
|
```ruby
|
|
69
|
-
|
|
91
|
+
# app/models/manager/service.rb
|
|
92
|
+
class Manager::Service < BugBunny::Resource
|
|
70
93
|
# 1. Configuración de Transporte
|
|
71
|
-
self.exchange = '
|
|
72
|
-
self.exchange_type = '
|
|
73
|
-
|
|
94
|
+
self.exchange = 'box_cluster_manager'
|
|
95
|
+
self.exchange_type = 'direct'
|
|
96
|
+
|
|
74
97
|
# 2. Configuración Lógica (Routing)
|
|
75
|
-
# Define
|
|
76
|
-
|
|
77
|
-
# - URL Base: 'users'
|
|
78
|
-
self.resource_name = 'users'
|
|
98
|
+
# Define la URL base y la routing key por defecto.
|
|
99
|
+
self.resource_name = 'services'
|
|
79
100
|
|
|
80
|
-
#
|
|
81
|
-
#
|
|
101
|
+
# 3. Wrapping de Parámetros (Opcional)
|
|
102
|
+
# Por defecto usa el nombre del modelo sin módulo (Manager::Service -> 'service').
|
|
103
|
+
# Puedes forzarlo con:
|
|
104
|
+
# self.param_key = 'docker_service'
|
|
82
105
|
end
|
|
83
106
|
```
|
|
84
107
|
|
|
85
|
-
###
|
|
108
|
+
### CRUD RESTful
|
|
86
109
|
|
|
87
|
-
|
|
110
|
+
Las operaciones de Ruby se traducen a verbos HTTP sobre AMQP.
|
|
88
111
|
|
|
89
112
|
```ruby
|
|
90
|
-
# ---
|
|
91
|
-
# Envia: GET
|
|
92
|
-
# Routing Key: "
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
#
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
#
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
#
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
# --- DESTROY ---
|
|
114
|
-
# Envia: DELETE users/123
|
|
115
|
-
# Routing Key: "users"
|
|
116
|
-
user.destroy
|
|
113
|
+
# --- LEER (GET) ---
|
|
114
|
+
# Envia: GET services
|
|
115
|
+
# Routing Key: "services"
|
|
116
|
+
services = Manager::Service.all
|
|
117
|
+
|
|
118
|
+
# Envia: GET services/123
|
|
119
|
+
service = Manager::Service.find('123')
|
|
120
|
+
|
|
121
|
+
# --- CREAR (POST) ---
|
|
122
|
+
# Envia: POST services
|
|
123
|
+
# Body: { "service": { "name": "nginx", "replicas": 3 } }
|
|
124
|
+
# Nota: Envuelve los params automáticamente en la clave 'service'.
|
|
125
|
+
svc = Manager::Service.create(name: 'nginx', replicas: 3)
|
|
126
|
+
|
|
127
|
+
# --- ACTUALIZAR (PUT) ---
|
|
128
|
+
# Envia: PUT services/123
|
|
129
|
+
# Body: { "service": { "replicas": 5 } }
|
|
130
|
+
svc.update(replicas: 5)
|
|
131
|
+
|
|
132
|
+
# --- ELIMINAR (DELETE) ---
|
|
133
|
+
# Envia: DELETE services/123
|
|
134
|
+
svc.destroy
|
|
117
135
|
```
|
|
118
136
|
|
|
119
|
-
###
|
|
120
|
-
|
|
121
|
-
Tienes 3 formas de controlar la `routing_key` hacia donde se envían los mensajes:
|
|
137
|
+
### Contexto Dinámico (`.with`)
|
|
122
138
|
|
|
123
|
-
|
|
124
|
-
| :--- | :--- | :--- | :--- |
|
|
125
|
-
| **1. Dinámico** | `resource_name` | (Por defecto) Usa el nombre del recurso. | `self.resource_name = 'users'` -> Key `users` |
|
|
126
|
-
| **2. Estático** | `routing_key` | Fuerza TODO a una sola cola. | `self.routing_key = 'cola_manager'` |
|
|
127
|
-
| **3. Temporal** | `.with(...)` | Override solo para esa petición. | `User.with(routing_key: 'urgent').create` |
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## 🔌 Modo Publisher (Cliente Manual)
|
|
132
|
-
|
|
133
|
-
Si no necesitas mapear un recurso o quieres enviar mensajes crudos, utiliza `BugBunny::Client`. Soporta semántica REST pasando el argumento `method:`.
|
|
134
|
-
|
|
135
|
-
### 1. Instanciar el Cliente
|
|
136
|
-
|
|
137
|
-
```ruby
|
|
138
|
-
client = BugBunny::Client.new(pool: BUG_BUNNY_POOL) do |conn|
|
|
139
|
-
# Puedes inyectar middlewares aquí
|
|
140
|
-
conn.use BugBunny::Middleware::JsonResponse
|
|
141
|
-
end
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### 2. Request (RPC Síncrono)
|
|
145
|
-
|
|
146
|
-
Envía el mensaje, **bloquea el hilo** y espera la respuesta JSON. Ideal para obtener datos.
|
|
139
|
+
Puedes cambiar la configuración (Routing Key, Exchange) para una operación específica sin afectar al modelo global. El contexto se mantiene durante el ciclo de vida del objeto.
|
|
147
140
|
|
|
148
141
|
```ruby
|
|
149
|
-
#
|
|
150
|
-
|
|
151
|
-
puts response['body']
|
|
142
|
+
# La instancia nace sabiendo que pertenece a la routing_key 'urgent'
|
|
143
|
+
svc = Manager::Service.with(routing_key: 'urgent').new(name: 'redis')
|
|
152
144
|
|
|
153
|
-
#
|
|
154
|
-
response = client.request('math/calc', method: :post, body: { a: 10, b: 20 })
|
|
145
|
+
# ... lógica de negocio ...
|
|
155
146
|
|
|
156
|
-
#
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
# DELETE (Borrar)
|
|
160
|
-
client.request('users/123', method: :delete)
|
|
147
|
+
# Al guardar, BugBunny recuerda el contexto y envía a 'urgent'
|
|
148
|
+
svc.save
|
|
149
|
+
# Log: [BugBunny] [POST] '/services' | Routing Key: 'urgent'
|
|
161
150
|
```
|
|
162
151
|
|
|
163
|
-
|
|
152
|
+
---
|
|
164
153
|
|
|
165
|
-
|
|
154
|
+
## 📡 Modo Servidor (Worker & Router)
|
|
166
155
|
|
|
167
|
-
|
|
168
|
-
# Enviar log o evento
|
|
169
|
-
client.publish('logs/error', method: :post, body: { msg: 'Disk full' })
|
|
170
|
-
```
|
|
156
|
+
BugBunny incluye un **Router Inteligente** que despacha mensajes a controladores basándose en el Verbo y el Path, imitando a Rails.
|
|
171
157
|
|
|
172
|
-
###
|
|
158
|
+
### 1. El Controlador (`app/rabbit/controllers/`)
|
|
173
159
|
|
|
174
|
-
|
|
160
|
+
Hereda de `BugBunny::Controller`. Tienes acceso a `params`, `before_action` y `rescue_from`.
|
|
175
161
|
|
|
176
162
|
```ruby
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
# Metadatos AMQP
|
|
182
|
-
req.priority = 9 # Alta prioridad (0-9)
|
|
183
|
-
req.expiration = '5000' # TTL 5 segundos (ms)
|
|
184
|
-
req.app_id = 'web-frontend'
|
|
185
|
-
req.headers['X-Trace-Id'] = 'abc-123'
|
|
186
|
-
end
|
|
187
|
-
```
|
|
163
|
+
# app/rabbit/controllers/services_controller.rb
|
|
164
|
+
class ServicesController < BugBunny::Controller
|
|
165
|
+
# Callbacks
|
|
166
|
+
before_action :set_service, only: %i[show update destroy]
|
|
188
167
|
|
|
189
|
-
|
|
168
|
+
# GET services
|
|
169
|
+
def index
|
|
170
|
+
render status: 200, json: DockerService.all
|
|
171
|
+
end
|
|
190
172
|
|
|
191
|
-
|
|
173
|
+
# POST services
|
|
174
|
+
def create
|
|
175
|
+
# BugBunny wrappea los params automáticamente en el Resource.
|
|
176
|
+
# Aquí los consumimos con seguridad usando Strong Parameters simulados o hash access.
|
|
177
|
+
# params[:service] estará disponible gracias al param_key del Resource.
|
|
192
178
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
| `method` | `Symbol` | Verbo HTTP (`:get`, `:post`, `:put`, `:delete`). | `:get` (en request) |
|
|
197
|
-
| `exchange` | `String` | Nombre del Exchange destino. | `''` (Default Ex) |
|
|
198
|
-
| `routing_key` | `String` | Clave de ruteo. Si falta, usa el `path`. | `path` |
|
|
199
|
-
| `headers` | `Hash` | Headers personalizados. | `{}` |
|
|
200
|
-
| `timeout` | `Integer` | (Solo RPC) Segundos máx de espera. | Config global |
|
|
201
|
-
| `app_id` | `String` | ID de la aplicación origen. | `nil` |
|
|
202
|
-
| `priority` | `Integer` | Prioridad del mensaje (0-9). | `0` |
|
|
203
|
-
| `expiration` | `String` | TTL del mensaje en ms. | `nil` |
|
|
179
|
+
result = DockerService.create(params[:service])
|
|
180
|
+
render status: 201, json: result
|
|
181
|
+
end
|
|
204
182
|
|
|
205
|
-
|
|
183
|
+
private
|
|
206
184
|
|
|
207
|
-
|
|
185
|
+
def set_service
|
|
186
|
+
# params[:id] se extrae automágicamente de la URL (Route Param)
|
|
187
|
+
@service = DockerService.find(params[:id])
|
|
208
188
|
|
|
209
|
-
|
|
189
|
+
unless @service
|
|
190
|
+
render status: 404, json: { error: "Service not found" }
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
```
|
|
210
195
|
|
|
211
|
-
###
|
|
196
|
+
### 2. Manejo de Errores (`rescue_from`)
|
|
212
197
|
|
|
213
|
-
|
|
198
|
+
Puedes definir un `ApplicationController` base para manejar errores de forma centralizada y declarativa.
|
|
214
199
|
|
|
215
200
|
```ruby
|
|
216
|
-
# app/rabbit/controllers/
|
|
217
|
-
class
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
users = User.where(active: params[:active])
|
|
222
|
-
render status: 200, json: users
|
|
201
|
+
# app/rabbit/controllers/application.rb
|
|
202
|
+
class ApplicationController < BugBunny::Controller
|
|
203
|
+
# Manejo específico
|
|
204
|
+
rescue_from ActiveRecord::RecordNotFound do
|
|
205
|
+
render status: :not_found, json: { error: "Resource missing" }
|
|
223
206
|
end
|
|
224
207
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
user = User.find(params[:id])
|
|
228
|
-
render status: 200, json: user
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
# POST users
|
|
232
|
-
def create
|
|
233
|
-
user = User.new(params)
|
|
234
|
-
if user.save
|
|
235
|
-
render status: 201, json: user
|
|
236
|
-
else
|
|
237
|
-
# Estos errores se propagan como BugBunny::UnprocessableEntity
|
|
238
|
-
render status: 422, json: { errors: user.errors }
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
# PUT users/123
|
|
243
|
-
def update
|
|
244
|
-
# ...
|
|
208
|
+
rescue_from ActiveModel::ValidationError do |e|
|
|
209
|
+
render status: :unprocessable_entity, json: e.model.errors
|
|
245
210
|
end
|
|
246
211
|
|
|
247
|
-
#
|
|
248
|
-
|
|
249
|
-
|
|
212
|
+
# Catch-all (Red de seguridad)
|
|
213
|
+
rescue_from StandardError do |e|
|
|
214
|
+
BugBunny.configuration.logger.error(e)
|
|
215
|
+
render status: :internal_server_error, json: { error: "Internal Error" }
|
|
250
216
|
end
|
|
251
217
|
end
|
|
252
218
|
```
|
|
253
219
|
|
|
254
|
-
###
|
|
220
|
+
### 3. Tabla de Ruteo (Convención)
|
|
255
221
|
|
|
256
|
-
El Router
|
|
222
|
+
El Router infiere la acción automáticamente:
|
|
257
223
|
|
|
258
|
-
|
|
|
224
|
+
| Verbo | URL Pattern | Controlador | Acción |
|
|
259
225
|
| :--- | :--- | :--- | :--- |
|
|
260
|
-
| `GET` | `
|
|
261
|
-
| `GET` | `
|
|
262
|
-
| `POST` | `
|
|
263
|
-
| `PUT` | `
|
|
264
|
-
| `DELETE` | `
|
|
265
|
-
| `POST` | `
|
|
266
|
-
|
|
267
|
-
### 3. Ejecutar el Worker
|
|
268
|
-
|
|
269
|
-
```bash
|
|
270
|
-
bundle exec rake bug_bunny:work
|
|
271
|
-
```
|
|
226
|
+
| `GET` | `services` | `ServicesController` | `index` |
|
|
227
|
+
| `GET` | `services/12` | `ServicesController` | `show` |
|
|
228
|
+
| `POST` | `services` | `ServicesController` | `create` |
|
|
229
|
+
| `PUT` | `services/12` | `ServicesController` | `update` |
|
|
230
|
+
| `DELETE` | `services/12` | `ServicesController` | `destroy` |
|
|
231
|
+
| `POST` | `services/12/restart` | `ServicesController` | `restart` (Custom) |
|
|
272
232
|
|
|
273
233
|
---
|
|
274
234
|
|
|
275
|
-
##
|
|
235
|
+
## 🔌 Modo Publisher (Cliente Manual)
|
|
236
|
+
|
|
237
|
+
Si necesitas enviar mensajes crudos fuera de la lógica Resource, usa `BugBunny::Client`.
|
|
276
238
|
|
|
277
|
-
|
|
239
|
+
```ruby
|
|
240
|
+
client = BugBunny::Client.new(pool: BUG_BUNNY_POOL)
|
|
241
|
+
|
|
242
|
+
# --- REQUEST (Síncrono / RPC) ---
|
|
243
|
+
# Espera la respuesta. Lanza BugBunny::RequestTimeout si falla.
|
|
244
|
+
response = client.request('services/123/logs',
|
|
245
|
+
method: :get,
|
|
246
|
+
exchange: 'logs_exchange',
|
|
247
|
+
timeout: 5
|
|
248
|
+
)
|
|
249
|
+
puts response['body']
|
|
278
250
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
251
|
+
# --- PUBLISH (Asíncrono / Fire-and-Forget) ---
|
|
252
|
+
# No espera respuesta.
|
|
253
|
+
client.publish('audit/events',
|
|
254
|
+
method: :post,
|
|
255
|
+
body: { event: 'login', user_id: 1 }
|
|
256
|
+
)
|
|
257
|
+
```
|
|
285
258
|
|
|
286
259
|
---
|
|
287
260
|
|
|
288
|
-
##
|
|
261
|
+
## 🏗 Arquitectura REST-over-AMQP
|
|
289
262
|
|
|
290
|
-
BugBunny
|
|
263
|
+
BugBunny desacopla el transporte de la lógica usando headers estándar.
|
|
291
264
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
265
|
+
1. **Semántica:** El mensaje lleva headers `type` (URL) y `x-http-method` (Verbo).
|
|
266
|
+
2. **Ruteo:** El consumidor lee estos headers y ejecuta el controlador correspondiente.
|
|
267
|
+
3. **Parametros:** `params` unifica:
|
|
268
|
+
* **Route Params:** `services/123` -> `params[:id] = 123`
|
|
269
|
+
* **Query Params:** `services?force=true` -> `params[:force] = true`
|
|
270
|
+
* **Body:** Payload JSON fusionado en el hash.
|
|
297
271
|
|
|
298
|
-
|
|
299
|
-
conn.use BugBunny::Middleware::JsonResponse
|
|
300
|
-
end
|
|
301
|
-
```
|
|
272
|
+
### Logs Estructurados
|
|
302
273
|
|
|
303
|
-
|
|
274
|
+
Facilita el debugging mostrando claramente qué recurso se está tocando y por dónde viaja.
|
|
304
275
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
* `BugBunny::UnprocessableEntity` (422) - Incluye errores de validación.
|
|
309
|
-
* `BugBunny::InternalServerError` (500)
|
|
276
|
+
```text
|
|
277
|
+
[BugBunny] [POST] '/services' | Exchange: 'cluster' (Type: direct) | Routing Key: 'node-1'
|
|
278
|
+
```
|
|
310
279
|
|
|
311
280
|
---
|
|
312
281
|
|
data/lib/bug_bunny/config.rb
CHANGED
|
@@ -26,6 +26,10 @@ module BugBunny
|
|
|
26
26
|
# @return [Logger] Instancia del logger para depuración (default: Logger a STDOUT).
|
|
27
27
|
attr_accessor :logger
|
|
28
28
|
|
|
29
|
+
# @return [Logger] Logger específico para el driver Bunny (Conexión, Heartbeats, Frames).
|
|
30
|
+
# Se recomienda nivel WARN para evitar ruido.
|
|
31
|
+
attr_accessor :bunny_logger
|
|
32
|
+
|
|
29
33
|
# @return [Boolean] Si `true`, Bunny intentará reconectar automáticamente ante fallos de red (default: true).
|
|
30
34
|
attr_accessor :automatically_recover
|
|
31
35
|
|
|
@@ -58,7 +62,13 @@ module BugBunny
|
|
|
58
62
|
|
|
59
63
|
# Inicializa la configuración con valores por defecto seguros.
|
|
60
64
|
def initialize
|
|
65
|
+
# Logger de la Aplicación (BugBunny) -> INFO (Ves tus requests)
|
|
61
66
|
@logger = Logger.new(STDOUT)
|
|
67
|
+
@logger.level = Logger::INFO
|
|
68
|
+
|
|
69
|
+
# Logger del Driver (Bunny) -> WARN (Oculta el ruido de "handle_frame")
|
|
70
|
+
@bunny_logger = Logger.new(STDOUT)
|
|
71
|
+
@bunny_logger.level = Logger::WARN
|
|
62
72
|
@automatically_recover = true
|
|
63
73
|
@network_recovery_interval = 5
|
|
64
74
|
@connection_timeout = 10
|