bug_bunny 3.0.0 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e154bfecb70c1fc85408e87876976dfc8c64c01c2816c4f811a05e39e8432f9
4
- data.tar.gz: 3b4e1508cd1a7f019fb638831c58117d00c46729b4f6bad4f8ecaf1b75914b47
3
+ metadata.gz: 730ae48562650742b536036de0db8b811efa48855790ef08bffc15713867654e
4
+ data.tar.gz: c4d16c6b17307831dd9cfc3be7ef2f78ecc52254034ded5187b2a19f00490aa3
5
5
  SHA512:
6
- metadata.gz: b43ec72552e6d17601665f7640aedd1e9c390463f6df5ca950b082e17316e387d0a10fa9e5ddfd3611d3f928a5d7d2af71367fa6c5409ba1f242402bd46843a1
7
- data.tar.gz: cdd64f5401a653a0fe839ea2a3cf926e1af7de6e8498892bbd20876ea2ed808f97d4db1daa1a31f70c54533a00f73e834a547943d34f8a95543b1befeb5a9591
6
+ metadata.gz: 5551a1bff89d318faf4155dead6e042ac991b57a30459efa2bfcad9029191b12391e6e058e275dda39bdaa4ed7cd2413e46ececa048905836009e4294b8d85e2
7
+ data.tar.gz: dd6af676b128f77d01c885d1107b773080d3ebd80b0a49477f3f6d4db511f91acdf8d2775281fa4cae529e17161cf7180caf41c983aece183112f6ab93fedf69
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.0.1] - 2026-02-10
4
+
5
+ ### 🚀 Features: RESTful Architecture
6
+ * **HTTP Verbs over AMQP:** Implemented support for semantic HTTP verbs (`GET`, `POST`, `PUT`, `DELETE`) within AMQP headers (`x-http-method`). This enables a true RESTful design over RabbitMQ.
7
+ * **Smart Router:** The `BugBunny::Consumer` now behaves like a Rails Router. It automatically infers the controller action based on the combination of the **Verb** and the **URL Path** (e.g., `GET users/1` dispatches to `show`, `POST users` to `create`).
8
+ * **Resource CRUD Mapping:** `BugBunny::Resource` now maps Ruby operations to their specific REST verbs:
9
+ * `create` -> `POST`
10
+ * `update` -> `PUT`
11
+ * `destroy` -> `DELETE`
12
+ * `find/where` -> `GET`.
13
+
14
+ ### 🛠 Improvements
15
+ * **Client API:** Updated `BugBunny::Client#request` and `#publish` to accept a `method:` argument (e.g., `client.request('users', method: :post)`), giving developers full control over the request semantics without changing the method signature.
16
+ * **Request Metadata:** `BugBunny::Request` now handles the `method` attribute and ensures it is properly injected into the AMQP headers for the consumer to read.
17
+
3
18
  ## [3.0.0] - 2026-02-05
4
19
 
5
20
  ### ⚠ Breaking Changes
data/README.md CHANGED
@@ -2,7 +2,9 @@
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"**. Abstrae la complejidad de colas y exchanges transformando patrones de mensajería en una arquitectura **RESTful simulada**, donde los mensajes contienen "URLs" y "Query Params" que son enrutados automáticamente a controladores.
5
+ Su filosofía es **"Active Record over AMQP"**. Abstrae la complejidad de colas y exchanges transformando patrones de mensajería en una arquitectura **RESTful simulada**.
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.
6
8
 
7
9
  ---
8
10
 
@@ -20,7 +22,7 @@ Ejecuta el bundle:
20
22
  bundle install
21
23
  ```
22
24
 
23
- Corre el instalador para generar la configuración:
25
+ Corre el instalador para generar la configuración inicial:
24
26
 
25
27
  ```bash
26
28
  rails g bug_bunny:install
@@ -30,11 +32,9 @@ rails g bug_bunny:install
30
32
 
31
33
  ## ⚙️ Configuración
32
34
 
33
- Configura tus credenciales y el Pool de conexiones en el inicializador.
35
+ Configura tus credenciales y el Pool de conexiones en el inicializador `config/initializers/bug_bunny.rb`.
34
36
 
35
37
  ```ruby
36
- # config/initializers/bug_bunny.rb
37
-
38
38
  BugBunny.configure do |config|
39
39
  config.host = ENV.fetch('RABBITMQ_HOST', 'localhost')
40
40
  config.username = ENV.fetch('RABBITMQ_USER', 'guest')
@@ -46,7 +46,9 @@ BugBunny.configure do |config|
46
46
  config.network_recovery_interval = 5
47
47
  end
48
48
 
49
- # Definimos el Pool Global (Vital para Puma/Sidekiq)
49
+ # ⚠️ CRÍTICO: Definimos el Pool Global
50
+ # Es vital usar ConnectionPool para garantizar la seguridad en entornos
51
+ # multi-hilo como Puma o Sidekiq.
50
52
  BUG_BUNNY_POOL = ConnectionPool.new(size: ENV.fetch('RAILS_MAX_THREADS', 5).to_i, timeout: 5) do
51
53
  BugBunny.create_connection
52
54
  end
@@ -59,128 +61,152 @@ BugBunny::Resource.connection_pool = BUG_BUNNY_POOL
59
61
 
60
62
  ## 🚀 Modo Resource (ORM / Active Record)
61
63
 
62
- Define modelos que actúan como proxis de recursos remotos. BugBunny separa la **Lógica de Transporte** (RabbitMQ) de la **Lógica de Aplicación** (Controladores).
64
+ Define modelos que actúan como proxies de recursos remotos. BugBunny separa la **Lógica de Transporte** (RabbitMQ) de la **Lógica de Aplicación** (Controladores).
63
65
 
64
- ### Escenario A: Routing Dinámico (Topic / Estándar)
65
- Ideal cuando quieres enrutar por acción. La Routing Key se genera automáticamente usando `resource_name.action`.
66
+ ### Definición del Modelo
66
67
 
67
68
  ```ruby
68
69
  class RemoteUser < BugBunny::Resource
69
- # --- Configuración ---
70
+ # 1. Configuración de Transporte
70
71
  self.exchange = 'app.topic'
71
72
  self.exchange_type = 'topic'
72
73
 
73
- # Define el nombre lógico del recurso.
74
- # 1. Routing Key: 'users.create', 'users.show.12'
75
- # 2. Header Type: 'users/create', 'users/show/12'
74
+ # 2. Configuración Lógica (Routing)
75
+ # Define el nombre del recurso. Se usa para:
76
+ # - Routing Key automática: 'users' (Topic)
77
+ # - URL Base: 'users'
76
78
  self.resource_name = 'users'
77
79
 
78
- # No necesitas definir atributos, BugBunny soporta atributos dinámicos (Schema-less)
79
- end
80
- ```
81
-
82
- ### Escenario B: Routing Estático (Direct / Cola Dedicada)
83
- Ideal cuando quieres enviar todo a una cola específica (ej: un Manager), independientemente de la acción.
84
-
85
- ```ruby
86
- class BoxManager < BugBunny::Resource
87
- # --- Configuración ---
88
- self.exchange = 'warehouse.direct'
89
- self.exchange_type = 'direct'
90
-
91
- # FORZAMOS LA ROUTING KEY.
92
- # Todo viaja con esta key, sin importar la acción.
93
- self.routing_key = 'manager_queue'
94
-
95
- # Define el nombre lógico para el Controlador.
96
- # Header Type: 'box_manager/create', 'box_manager/show/12'
97
- self.resource_name = 'box_manager'
80
+ # Nota: BugBunny es Schema-less. No necesitas definir atributos.
81
+ # Soporta acceso dinámico: user.Name, user.email, etc.
98
82
  end
99
83
  ```
100
84
 
101
- ### Consumiendo el Servicio (CRUD)
85
+ ### Consumiendo el Servicio (CRUD RESTful)
102
86
 
103
- La API simula ActiveRecord. Por debajo, construye una "URL" en el header `type` para que el consumidor sepa qué hacer.
87
+ BugBunny traduce automáticamente las llamadas de Ruby a peticiones HTTP simuladas.
104
88
 
105
89
  ```ruby
106
- # --- READ (Colección con Filtros) ---
107
- # Header Type: "users/index?active=true" (Query Params)
108
- # Routing Key: "users.index" (Dinámico) o "manager_queue" (Estático)
90
+ # --- READ COLLECTION (Index) ---
91
+ # Envia: GET users?active=true
92
+ # Routing Key: "users"
109
93
  users = RemoteUser.where(active: true)
110
94
 
111
- # --- READ (Singular) ---
112
- # Header Type: "users/show/123" (ID en Path)
113
- # Routing Key: "users.show.123" (Dinámico) o "manager_queue" (Estático)
95
+ # --- READ MEMBER (Show) ---
96
+ # Envia: GET users/123
97
+ # Routing Key: "users"
114
98
  user = RemoteUser.find(123)
115
- puts user.name # Acceso dinámico a atributos
99
+ puts user.email
116
100
 
117
101
  # --- CREATE ---
118
- # Header Type: "users/create"
119
- user = RemoteUser.create(email: "test@test.com")
102
+ # Envia: POST users
103
+ # Routing Key: "users"
104
+ # Body: { "email": "test@test.com", "role": "admin" }
105
+ user = RemoteUser.create(email: "test@test.com", role: "admin")
120
106
 
121
107
  # --- UPDATE ---
122
- # Header Type: "users/update/123"
108
+ # Envia: PUT users/123
109
+ # Routing Key: "users"
123
110
  user.update(email: "edit@test.com")
124
- # Dirty Tracking: Solo se envían los atributos modificados.
111
+ # Dirty Tracking: Solo se envían los campos modificados.
125
112
 
126
113
  # --- DESTROY ---
127
- # Header Type: "users/destroy/123"
114
+ # Envia: DELETE users/123
115
+ # Routing Key: "users"
128
116
  user.destroy
129
117
  ```
130
118
 
119
+ ### Estrategias de Routing
120
+
121
+ Tienes 3 formas de controlar la `routing_key` hacia donde se envían los mensajes:
122
+
123
+ | Nivel | Método | Descripción | Ejemplo Config |
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
+
131
129
  ---
132
130
 
133
131
  ## 🔌 Modo Publisher (Cliente Manual)
134
132
 
135
- Si no necesitas mapear un recurso o quieres enviar mensajes crudos ("Fire-and-Forget"), puedes usar `BugBunny::Client` directamente.
133
+ Si no necesitas mapear un recurso o quieres enviar mensajes crudos, utiliza `BugBunny::Client`. Soporta semántica REST pasando el argumento `method:`.
136
134
 
137
135
  ### 1. Instanciar el Cliente
138
136
 
139
137
  ```ruby
140
- # Puedes inyectar middlewares personalizados aquí si lo deseas
141
138
  client = BugBunny::Client.new(pool: BUG_BUNNY_POOL) do |conn|
139
+ # Puedes inyectar middlewares aquí
142
140
  conn.use BugBunny::Middleware::JsonResponse
143
141
  end
144
142
  ```
145
143
 
146
- ### 2. Publicar Asíncronamente (Fire-and-Forget)
147
- Envía el mensaje y retorna inmediatamente. Ideal para eventos o logs.
144
+ ### 2. Request (RPC Síncrono)
145
+
146
+ Envía el mensaje, **bloquea el hilo** y espera la respuesta JSON. Ideal para obtener datos.
148
147
 
149
148
  ```ruby
150
- # publish(url_logica, opciones)
151
- client.publish('notifications/alert',
152
- exchange: 'events.topic',
153
- exchange_type: 'topic',
154
- routing_key: 'alerts.critical',
155
- body: { message: 'CPU High', server: 'web-1' }
156
- )
149
+ # GET (Leer)
150
+ response = client.request('users/123', method: :get)
151
+ puts response['body']
152
+
153
+ # POST (Crear / Ejecutar)
154
+ response = client.request('math/calc', method: :post, body: { a: 10, b: 20 })
155
+
156
+ # PUT (Actualizar)
157
+ client.request('users/123', method: :put, body: { active: true })
158
+
159
+ # DELETE (Borrar)
160
+ client.request('users/123', method: :delete)
157
161
  ```
158
162
 
159
- ### 3. Petición Síncrona (RPC)
160
- Envía el mensaje y bloquea el hilo esperando la respuesta del consumidor.
163
+ ### 3. Publish (Asíncrono / Fire-and-Forget)
164
+
165
+ Envía el mensaje y retorna inmediatamente. No espera respuesta. Por defecto usa `method: :post` si no se especifica.
161
166
 
162
167
  ```ruby
163
- begin
164
- # request(url_logica, opciones)
165
- response = client.request('math/calculate',
166
- exchange: 'rpc.direct',
167
- routing_key: 'calculator',
168
- body: { a: 10, b: 20 },
169
- timeout: 5 # Segundos de espera máxima
170
- )
171
-
172
- puts response['body'] # => { "result": 30 }
168
+ # Enviar log o evento
169
+ client.publish('logs/error', method: :post, body: { msg: 'Disk full' })
170
+ ```
173
171
 
174
- rescue BugBunny::RequestTimeout
175
- puts "El servidor tardó demasiado."
172
+ ### 4. Configuración Avanzada (Bloques)
173
+
174
+ Puedes usar un bloque para configurar opciones de bajo nivel de AMQP (prioridad, expiración, headers, app_id).
175
+
176
+ ```ruby
177
+ client.publish('jobs/process') do |req|
178
+ req.method = :post
179
+ req.body = { image_id: 99 }
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'
176
186
  end
177
187
  ```
178
188
 
189
+ ### 5. Referencia de Opciones
190
+
191
+ Estas opciones pueden pasarse como argumentos (`client.request(key: val)`) o dentro del bloque (`req.key = val`).
192
+
193
+ | Opción / Atributo | Tipo | Descripción | Default |
194
+ | :--- | :--- | :--- | :--- |
195
+ | `body` | `Hash/String` | El contenido del mensaje. | `nil` |
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` |
204
+
179
205
  ---
180
206
 
181
207
  ## 📡 Modo Servidor (El Worker)
182
208
 
183
- BugBunny incluye un **Router Inteligente** que parsea el header `type` (la URL simulada), extrae parámetros y despacha al controlador.
209
+ BugBunny incluye un **Router Inteligente** que funciona igual que el `config/routes.rb` de Rails. Infiere la acción basándose en el **Verbo HTTP** y la estructura de la **URL**.
184
210
 
185
211
  ### 1. Definir Controladores
186
212
 
@@ -190,26 +216,19 @@ Crea tus controladores en `app/rabbit/controllers/`. Heredan de `BugBunny::Contr
190
216
  # app/rabbit/controllers/users_controller.rb
191
217
  class UsersController < BugBunny::Controller
192
218
 
193
- # Acción para type: "users/index?active=true"
219
+ # GET users
194
220
  def index
195
- # params fusiona Query Params y Body
196
221
  users = User.where(active: params[:active])
197
222
  render status: 200, json: users
198
223
  end
199
224
 
200
- # Acción para type: "users/show/12"
225
+ # GET users/123
201
226
  def show
202
- # params[:id] se extrae automáticamente del Path de la URL
203
- user = User.find_by(id: params[:id])
204
-
205
- if user
206
- render status: 200, json: user
207
- else
208
- render status: 404, json: { error: 'Not Found' }
209
- end
227
+ user = User.find(params[:id])
228
+ render status: 200, json: user
210
229
  end
211
230
 
212
- # Acción para type: "users/create"
231
+ # POST users
213
232
  def create
214
233
  user = User.new(params)
215
234
  if user.save
@@ -219,10 +238,33 @@ class UsersController < BugBunny::Controller
219
238
  render status: 422, json: { errors: user.errors }
220
239
  end
221
240
  end
241
+
242
+ # PUT users/123
243
+ def update
244
+ # ...
245
+ end
246
+
247
+ # DELETE users/123
248
+ def destroy
249
+ # ...
250
+ end
222
251
  end
223
252
  ```
224
253
 
225
- ### 2. Ejecutar el Worker
254
+ ### 2. Tabla de Ruteo (Convención)
255
+
256
+ El Router despacha automáticamente según esta tabla:
257
+
258
+ | Header `x-http-method` | Header `type` (URL) | Controlador | Acción |
259
+ | :--- | :--- | :--- | :--- |
260
+ | `GET` | `users` | `UsersController` | `index` |
261
+ | `GET` | `users/12` | `UsersController` | `show` |
262
+ | `POST` | `users` | `UsersController` | `create` |
263
+ | `PUT` | `users/12` | `UsersController` | `update` |
264
+ | `DELETE` | `users/12` | `UsersController` | `destroy` |
265
+ | `POST` | `users/12/promote` | `UsersController` | `promote` (Custom) |
266
+
267
+ ### 3. Ejecutar el Worker
226
268
 
227
269
  ```bash
228
270
  bundle exec rake bug_bunny:work
@@ -232,21 +274,20 @@ bundle exec rake bug_bunny:work
232
274
 
233
275
  ## 🏗 Arquitectura REST-over-AMQP
234
276
 
235
- BugBunny desacopla el transporte de la lógica usando headers.
277
+ BugBunny desacopla el transporte de la lógica usando headers AMQP estándar.
236
278
 
237
- | Concepto | REST (HTTP) | BugBunny (AMQP) | Configuración |
238
- | :--- | :--- | :--- | :--- |
239
- | **Endpoint** | URL Path (`/users/1`) | Header `type` (`users/show/1`) | `resource_name` |
240
- | **Filtros** | Query String (`?active=true`) | Header `type` (`users/index?active=true`) | Automático (`where`) |
241
- | **Destino Físico** | IP/Dominio | Routing Key (`users.create` o `manager`) | `routing_key` (Estático) o `resource_name` (Dinámico) |
242
- | **Payload** | Body (JSON) | Body (JSON) | N/A |
243
- | **Status** | HTTP Code (200, 404) | JSON Response `status` | N/A |
279
+ | Concepto | REST (HTTP) | BugBunny (AMQP) |
280
+ | :--- | :--- | :--- |
281
+ | **Recurso** | `POST /users` | Header `type`: `users` + Header `x-http-method`: `POST` |
282
+ | **Parametros** | Query String / Body | Header `type` (Query) + Body (Payload) |
283
+ | **Destino** | DNS / IP | Routing Key (ej: `users`) |
284
+ | **Status** | HTTP Code (200, 404) | JSON Response `status` |
244
285
 
245
286
  ---
246
287
 
247
288
  ## 🛠 Middlewares
248
289
 
249
- BugBunny usa una pila de middlewares para procesar respuestas.
290
+ BugBunny usa una pila de middlewares para procesar peticiones y respuestas, permitiendo logging, manejo de errores y transformación de datos.
250
291
 
251
292
  ```ruby
252
293
  # Configuración global en el Resource
@@ -259,12 +300,13 @@ BugBunny::Resource.client_middleware do |conn|
259
300
  end
260
301
  ```
261
302
 
262
- ### Excepciones
303
+ ### Excepciones Soportadas
263
304
 
264
- * `BugBunny::UnprocessableEntity` (422): Error de validación.
265
- * `BugBunny::NotFound` (404): Recurso no encontrado.
266
- * `BugBunny::RequestTimeout`: Timeout RPC.
267
- * `BugBunny::CommunicationError`: Fallo de red RabbitMQ.
305
+ * `BugBunny::BadRequest` (400)
306
+ * `BugBunny::NotFound` (404)
307
+ * `BugBunny::RequestTimeout` (408)
308
+ * `BugBunny::UnprocessableEntity` (422) - Incluye errores de validación.
309
+ * `BugBunny::InternalServerError` (500)
268
310
 
269
311
  ---
270
312
 
@@ -4,31 +4,25 @@ require_relative 'middleware/stack'
4
4
  module BugBunny
5
5
  # Cliente principal para realizar peticiones a RabbitMQ.
6
6
  #
7
- # Implementa el patrón "Onion Middleware" (Arquitectura de Cebolla) similar a Faraday,
8
- # permitiendo interceptar, transformar y procesar tanto las peticiones salientes
9
- # como las respuestas entrantes mediante una pila de middlewares.
7
+ # Implementa el patrón "Onion Middleware" (Arquitectura de Cebolla) similar a Faraday.
8
+ # Mantiene una interfaz flexible donde el verbo HTTP se pasa como opción.
10
9
  #
11
- # @example Inicialización básica
12
- # client = BugBunny::Client.new(pool: MY_POOL)
10
+ # @example Petición RPC (GET)
11
+ # client.request('users/123', method: :get)
13
12
  #
14
- # @example Con Middlewares personalizados
15
- # client = BugBunny::Client.new(pool: MY_POOL) do |conn|
16
- # conn.use BugBunny::Middleware::RaiseError
17
- # conn.use BugBunny::Middleware::JsonResponse
18
- # conn.use BugBunny::Middleware::Logger, Rails.logger
19
- # end
13
+ # @example Publicación Fire-and-Forget (POST)
14
+ # client.publish('logs', method: :post, body: { msg: 'Error' })
20
15
  class Client
21
16
  # @return [ConnectionPool] El pool de conexiones subyacente a RabbitMQ.
22
17
  attr_reader :pool
23
18
 
24
- # @return [BugBunny::Middleware::Stack] La pila de middlewares configurada para este cliente.
19
+ # @return [BugBunny::Middleware::Stack] La pila de middlewares configurada.
25
20
  attr_reader :stack
26
21
 
27
22
  # Inicializa un nuevo cliente.
28
23
  #
29
24
  # @param pool [ConnectionPool] Pool de conexiones a RabbitMQ configurado previamente.
30
25
  # @yield [stack] Bloque opcional para configurar la pila de middlewares.
31
- # @yieldparam stack [BugBunny::Middleware::Stack] El objeto stack para registrar middlewares con {#use}.
32
26
  # @raise [ArgumentError] Si no se proporciona un `pool`.
33
27
  def initialize(pool:)
34
28
  raise ArgumentError, "BugBunny::Client requiere un 'pool:'" if pool.nil?
@@ -39,21 +33,16 @@ module BugBunny
39
33
 
40
34
  # Realiza una petición Síncrona (RPC / Request-Response).
41
35
  #
42
- # Envía un mensaje y bloquea la ejecución del hilo actual hasta recibir una respuesta
43
- # correlacionada del servidor o hasta que se supere el tiempo de espera (timeout).
36
+ # Envía un mensaje y bloquea la ejecución del hilo actual hasta recibir respuesta.
44
37
  #
45
- # @param url [String] La ruta o acción del mensaje (ej: 'users/create').
46
- # @param args [Hash] Opciones de configuración de la petición.
47
- # @option args [Object] :body El cuerpo del mensaje (Hash o String).
48
- # @option args [String] :exchange Nombre del exchange destino.
49
- # @option args [String] :exchange_type Tipo de exchange ('direct', 'topic', 'fanout').
50
- # @option args [String] :routing_key Routing key manual (opcional).
51
- # @option args [Integer] :timeout Tiempo máximo de espera en segundos antes de lanzar timeout.
52
- # @option args [Hash] :headers Headers AMQP adicionales para metadatos.
53
- # @yield [req] Bloque opcional para configurar el objeto Request directamente.
54
- # @yieldparam req [BugBunny::Request] Objeto request configurable.
55
- # @return [Hash] La respuesta del servidor, conteniendo habitualmente `status` y `body`.
56
- # @raise [BugBunny::RequestTimeout] Si no se recibe respuesta en el tiempo límite.
38
+ # @param url [String] La ruta del recurso (ej: 'users/1').
39
+ # @param args [Hash] Opciones de configuración.
40
+ # @option args [Symbol] :method El verbo HTTP (:get, :post, :put, :delete). Default: :get.
41
+ # @option args [Object] :body El cuerpo del mensaje.
42
+ # @option args [Hash] :headers Headers AMQP adicionales.
43
+ # @option args [Integer] :timeout Tiempo máximo de espera.
44
+ # @yield [req] Bloque para configurar el objeto Request directamente.
45
+ # @return [Hash] La respuesta del servidor.
57
46
  def request(url, **args)
58
47
  run_in_pool(:rpc, url, args) do |req|
59
48
  yield req if block_given?
@@ -62,13 +51,9 @@ module BugBunny
62
51
 
63
52
  # Realiza una publicación Asíncrona (Fire-and-Forget).
64
53
  #
65
- # Envía el mensaje al exchange y retorna el control inmediatamente sin esperar
66
- # ninguna confirmación o respuesta del consumidor.
67
- #
68
- # @param url [String] La ruta o acción del mensaje.
69
- # @param args [Hash] Mismas opciones que {#request}, excepto `:timeout` (no aplica).
70
- # @yield [req] Bloque opcional para configurar el objeto Request.
71
- # @yieldparam req [BugBunny::Request] Objeto request configurable.
54
+ # @param url [String] La ruta del evento/recurso.
55
+ # @param args [Hash] Mismas opciones que {#request}, excepto `:timeout`.
56
+ # @yield [req] Bloque para configurar el objeto Request.
72
57
  # @return [void]
73
58
  def publish(url, **args)
74
59
  run_in_pool(:fire, url, args) do |req|
@@ -78,16 +63,14 @@ module BugBunny
78
63
 
79
64
  private
80
65
 
81
- # Ejecuta la lógica de envío dentro del contexto del Pool y aplica la cadena de middlewares.
82
- #
83
- # @param method_name [Symbol] El método a invocar en el Producer (:rpc o :fire).
84
- # @param url [String] La URL/Acción del request.
85
- # @param args [Hash] Argumentos pasados al método público.
66
+ # Ejecuta la lógica de envío dentro del contexto del Pool.
67
+ # Mapea los argumentos al objeto Request y ejecuta la cadena de middlewares.
86
68
  def run_in_pool(method_name, url, args)
87
69
  # 1. Builder del Request
88
70
  req = BugBunny::Request.new(url)
89
71
 
90
72
  # 2. Syntactic Sugar: Mapeo de argumentos a atributos del Request
73
+ req.method = args[:method] if args[:method]
91
74
  req.body = args[:body] if args[:body]
92
75
  req.exchange = args[:exchange] if args[:exchange]
93
76
  req.exchange_type = args[:exchange_type] if args[:exchange_type]