bug_bunny 2.0.2 → 3.0.0
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 +23 -1
- data/README.md +222 -132
- data/bin_client.rb +51 -0
- data/bin_suite.rb +77 -0
- data/bin_worker.rb +20 -0
- data/initializer_example.rb +27 -0
- data/lib/bug_bunny/client.rb +119 -0
- data/lib/bug_bunny/config.rb +74 -3
- data/lib/bug_bunny/consumer.rb +151 -0
- data/lib/bug_bunny/controller.rb +74 -49
- data/lib/bug_bunny/exception.rb +81 -14
- data/lib/bug_bunny/middleware/json_response.rb +74 -0
- data/lib/bug_bunny/middleware/raise_error.rb +71 -0
- data/lib/bug_bunny/middleware/stack.rb +50 -0
- data/lib/bug_bunny/producer.rb +130 -0
- data/lib/bug_bunny/rabbit.rb +70 -300
- data/lib/bug_bunny/railtie.rb +54 -0
- data/lib/bug_bunny/request.rb +128 -0
- data/lib/bug_bunny/resource.rb +361 -156
- data/lib/bug_bunny/session.rb +82 -0
- data/lib/bug_bunny/version.rb +1 -1
- data/lib/bug_bunny.rb +104 -16
- data/lib/generators/bug_bunny/install/install_generator.rb +48 -0
- data/lib/generators/bug_bunny/install/templates/initializer.rb +61 -0
- data/test_controller.rb +49 -0
- data/test_helper.rb +20 -0
- data/test_resource.rb +22 -0
- metadata +178 -4
- data/lib/bug_bunny/publisher.rb +0 -108
data/lib/bug_bunny/version.rb
CHANGED
data/lib/bug_bunny.rb
CHANGED
|
@@ -1,25 +1,113 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
1
|
require 'bunny'
|
|
2
|
+
require 'logger'
|
|
3
|
+
require 'connection_pool'
|
|
4
|
+
|
|
4
5
|
require_relative 'bug_bunny/version'
|
|
5
6
|
require_relative 'bug_bunny/config'
|
|
6
|
-
require_relative 'bug_bunny/controller'
|
|
7
|
-
require_relative 'bug_bunny/publisher'
|
|
8
7
|
require_relative 'bug_bunny/exception'
|
|
9
|
-
require_relative 'bug_bunny/
|
|
8
|
+
require_relative 'bug_bunny/request'
|
|
9
|
+
require_relative 'bug_bunny/session'
|
|
10
|
+
require_relative 'bug_bunny/producer'
|
|
11
|
+
require_relative 'bug_bunny/client'
|
|
10
12
|
require_relative 'bug_bunny/resource'
|
|
13
|
+
require_relative 'bug_bunny/rabbit'
|
|
14
|
+
require_relative 'bug_bunny/consumer'
|
|
15
|
+
require_relative 'bug_bunny/controller'
|
|
16
|
+
|
|
17
|
+
require_relative 'bug_bunny/middleware/stack'
|
|
18
|
+
require_relative 'bug_bunny/middleware/raise_error'
|
|
19
|
+
require_relative 'bug_bunny/middleware/json_response'
|
|
11
20
|
|
|
21
|
+
# Punto de entrada principal y Namespace de la gema BugBunny.
|
|
22
|
+
#
|
|
23
|
+
# BugBunny es un framework ligero sobre RabbitMQ diseñado para simplificar
|
|
24
|
+
# patrones de mensajería (RPC y Fire-and-Forget) en aplicaciones Ruby on Rails.
|
|
25
|
+
#
|
|
26
|
+
# @see BugBunny::Client Para enviar mensajes.
|
|
27
|
+
# @see BugBunny::Resource Para mapear modelos remotos.
|
|
28
|
+
# @see BugBunny::Consumer Para procesar mensajes entrantes.
|
|
12
29
|
module BugBunny
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
# Factory method (Alias) para instanciar un nuevo Cliente.
|
|
31
|
+
#
|
|
32
|
+
# @param args [Hash] Argumentos pasados al constructor de {BugBunny::Client}.
|
|
33
|
+
# @return [BugBunny::Client] Una nueva instancia del cliente.
|
|
34
|
+
def self.new(**args)
|
|
35
|
+
BugBunny::Client.new(**args)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Configura la librería globalmente.
|
|
39
|
+
#
|
|
40
|
+
# @example Configuración típica en un initializer
|
|
41
|
+
# BugBunny.configure do |config|
|
|
42
|
+
# config.host = 'localhost'
|
|
43
|
+
# config.username = 'guest'
|
|
44
|
+
# config.rpc_timeout = 5
|
|
45
|
+
# end
|
|
46
|
+
#
|
|
47
|
+
# @yield [config] Bloque de configuración.
|
|
48
|
+
# @yieldparam config [BugBunny::Config] Objeto de configuración global.
|
|
49
|
+
# @return [BugBunny::Config] La configuración actualizada.
|
|
50
|
+
def self.configure
|
|
51
|
+
self.configuration ||= Config.new
|
|
52
|
+
yield(configuration)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Accesor al objeto de configuración global (Singleton).
|
|
56
|
+
#
|
|
57
|
+
# @return [BugBunny::Config] La instancia de configuración actual.
|
|
58
|
+
def self.configuration
|
|
59
|
+
@configuration ||= Config.new
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Cierra la conexión global mantenida por {BugBunny::Rabbit}.
|
|
63
|
+
# Útil para liberar recursos en scripts o tareas Rake al finalizar.
|
|
64
|
+
#
|
|
65
|
+
# @see BugBunny::Rabbit.disconnect
|
|
66
|
+
# @return [void]
|
|
67
|
+
def self.disconnect
|
|
68
|
+
BugBunny::Rabbit.disconnect
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Crea una nueva conexión a RabbitMQ (Bunny Session).
|
|
72
|
+
#
|
|
73
|
+
# Este método fusiona la configuración global por defecto con las opciones
|
|
74
|
+
# pasadas explícitamente como argumentos, dando prioridad a estas últimas.
|
|
75
|
+
#
|
|
76
|
+
# Maneja automáticamente el inicio de la conexión (`start`) y captura errores
|
|
77
|
+
# de red comunes envolviéndolos en excepciones de BugBunny.
|
|
78
|
+
#
|
|
79
|
+
# @param options [Hash] Opciones de conexión que sobrescriben la configuración global.
|
|
80
|
+
# @option options [String] :host Host de RabbitMQ.
|
|
81
|
+
# @option options [String] :vhost Virtual Host.
|
|
82
|
+
# @option options [String] :username Usuario.
|
|
83
|
+
# @option options [String] :password Contraseña.
|
|
84
|
+
# @option options [Logger] :logger Logger personalizado.
|
|
85
|
+
# @option options [Boolean] :automatically_recover (true/false).
|
|
86
|
+
# @option options [Integer] :network_recovery_interval Intervalo de reconexión.
|
|
87
|
+
# @option options [Integer] :connection_timeout Timeout de conexión TCP.
|
|
88
|
+
# @return [Bunny::Session] Una sesión de Bunny iniciada y lista para usar.
|
|
89
|
+
# @raise [BugBunny::CommunicationError] Si no se puede establecer la conexión TCP.
|
|
90
|
+
def self.create_connection(**options)
|
|
91
|
+
default = configuration
|
|
92
|
+
|
|
93
|
+
bunny = Bunny.new(
|
|
94
|
+
host: options[:host] || default.host,
|
|
95
|
+
username: options[:username] || default.username,
|
|
96
|
+
password: options[:password] || default.password,
|
|
97
|
+
vhost: options[:vhost] || default.vhost,
|
|
98
|
+
logger: options[:logger] || default.logger,
|
|
99
|
+
automatically_recover: options[:automatically_recover] || default.automatically_recover,
|
|
100
|
+
network_recovery_interval: options[:network_recovery_interval] || default.network_recovery_interval,
|
|
101
|
+
connection_timeout: options[:connection_timeout] || default.connection_timeout,
|
|
102
|
+
read_timeout: options[:read_timeout] || default.read_timeout,
|
|
103
|
+
write_timeout: options[:write_timeout] || default.write_timeout,
|
|
104
|
+
heartbeat: options[:heartbeat] || default.heartbeat,
|
|
105
|
+
continuation_timeout: options[:continuation_timeout] || default.continuation_timeout
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
bunny.start
|
|
109
|
+
bunny
|
|
110
|
+
rescue Timeout::Error, Bunny::ConnectionError => e
|
|
111
|
+
raise BugBunny::CommunicationError, e.message
|
|
24
112
|
end
|
|
25
113
|
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
|
|
5
|
+
module BugBunny
|
|
6
|
+
module Generators
|
|
7
|
+
# Generador de instalación estándar de Rails para BugBunny.
|
|
8
|
+
#
|
|
9
|
+
# Este generador se encarga de realizar el "scaffolding" inicial necesario para
|
|
10
|
+
# integrar la gema en una aplicación Rails existente.
|
|
11
|
+
#
|
|
12
|
+
# Acciones principales:
|
|
13
|
+
# 1. Crea el archivo de configuración (Initializer).
|
|
14
|
+
# 2. Establece la estructura de directorios para los controladores AMQP.
|
|
15
|
+
#
|
|
16
|
+
# @example Ejecución desde la terminal
|
|
17
|
+
# rails generate bug_bunny:install
|
|
18
|
+
class InstallGenerator < Rails::Generators::Base
|
|
19
|
+
# Define la raíz de los recursos para buscar las plantillas (templates).
|
|
20
|
+
# @api private
|
|
21
|
+
source_root File.expand_path('templates', __dir__)
|
|
22
|
+
|
|
23
|
+
desc "Instala la configuración inicial de BugBunny y crea la estructura de directorios."
|
|
24
|
+
|
|
25
|
+
# Genera el archivo de configuración inicial.
|
|
26
|
+
# Copia la plantilla `initializer.rb` a `config/initializers/bug_bunny.rb` en la app destino.
|
|
27
|
+
#
|
|
28
|
+
# @return [void]
|
|
29
|
+
def create_initializer
|
|
30
|
+
template 'initializer.rb', 'config/initializers/bug_bunny.rb'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Crea la estructura de carpetas necesaria para el patrón MVC de BugBunny.
|
|
34
|
+
#
|
|
35
|
+
# Genera:
|
|
36
|
+
# * `app/rabbit/controllers/`: Directorio donde vivirán los controladores de consumidores.
|
|
37
|
+
# * `.keep`: Archivo marcador para asegurar que Git rastree la carpeta aunque esté vacía.
|
|
38
|
+
#
|
|
39
|
+
# @return [void]
|
|
40
|
+
def create_directories
|
|
41
|
+
empty_directory "app/rabbit/controllers"
|
|
42
|
+
create_file "app/rabbit/controllers/.keep", ""
|
|
43
|
+
|
|
44
|
+
puts "🐰 BugBunny structure created successfully!"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# BugBunny Configuration
|
|
4
|
+
#
|
|
5
|
+
# Este archivo inicializador permite ajustar el comportamiento global de la conexión
|
|
6
|
+
# a RabbitMQ y los parámetros de rendimiento de los consumidores.
|
|
7
|
+
#
|
|
8
|
+
# Se recomienda encarecidamente utilizar variables de entorno (ENV) para gestionar
|
|
9
|
+
# las credenciales y evitar hardcodear secretos en el repositorio.
|
|
10
|
+
|
|
11
|
+
BugBunny.configure do |config|
|
|
12
|
+
# ==========================================
|
|
13
|
+
# 🔌 Conexión a RabbitMQ
|
|
14
|
+
# ==========================================
|
|
15
|
+
|
|
16
|
+
# Dirección IP o Hostname del servidor RabbitMQ.
|
|
17
|
+
config.host = ENV.fetch('RABBITMQ_HOST', 'localhost')
|
|
18
|
+
|
|
19
|
+
# Usuario para la autenticación (SASL).
|
|
20
|
+
config.username = ENV.fetch('RABBITMQ_USERNAME', 'guest')
|
|
21
|
+
|
|
22
|
+
# Contraseña del usuario.
|
|
23
|
+
config.password = ENV.fetch('RABBITMQ_PASSWORD', 'guest')
|
|
24
|
+
|
|
25
|
+
# Virtual Host (VHost) para aislar entornos (ej: '/', '/staging', '/prod').
|
|
26
|
+
config.vhost = ENV.fetch('RABBITMQ_VHOST', '/')
|
|
27
|
+
|
|
28
|
+
# ==========================================
|
|
29
|
+
# 🛡️ Resiliencia y Recuperación
|
|
30
|
+
# ==========================================
|
|
31
|
+
|
|
32
|
+
# Si es true, la librería intentará reconectar automáticamente los canales
|
|
33
|
+
# y recuperar las suscripciones si la conexión TCP se corta.
|
|
34
|
+
config.automatically_recover = true
|
|
35
|
+
|
|
36
|
+
# Tiempo de espera en segundos antes de intentar restablecer una conexión caída.
|
|
37
|
+
config.network_recovery_interval = 5
|
|
38
|
+
|
|
39
|
+
# ==========================================
|
|
40
|
+
# ⏱️ Timeouts
|
|
41
|
+
# ==========================================
|
|
42
|
+
|
|
43
|
+
# Tiempo máximo en segundos para establecer la conexión TCP inicial.
|
|
44
|
+
config.connection_timeout = 10
|
|
45
|
+
|
|
46
|
+
# Timeout crítico para llamadas RPC síncronas (Resource.find, Client.request).
|
|
47
|
+
# Si el worker remoto no responde dentro de este tiempo, el cliente lanzará
|
|
48
|
+
# una excepción `BugBunny::RequestTimeout`.
|
|
49
|
+
config.rpc_timeout = 10
|
|
50
|
+
|
|
51
|
+
# ==========================================
|
|
52
|
+
# 🚀 Rendimiento (QoS)
|
|
53
|
+
# ==========================================
|
|
54
|
+
|
|
55
|
+
# Channel Prefetch (QoS): Controla el "Backpressure".
|
|
56
|
+
# Define cuántos mensajes sin confirmar (unacked) puede tener un consumidor al mismo tiempo.
|
|
57
|
+
#
|
|
58
|
+
# * Valor bajo (1): Garantiza distribución justa (Round Robin) entre workers, pero menor throughput.
|
|
59
|
+
# * Valor alto (10-50): Mayor throughput, pero riesgo de sobrecargar un solo worker lento.
|
|
60
|
+
config.channel_prefetch = 10
|
|
61
|
+
end
|
data/test_controller.rb
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# test_controller.rb
|
|
2
|
+
require 'active_support/all'
|
|
3
|
+
require 'rack'
|
|
4
|
+
require_relative 'lib/bug_bunny'
|
|
5
|
+
|
|
6
|
+
module Rabbit
|
|
7
|
+
module Controllers
|
|
8
|
+
# Nota: BugBunny buscará "TestUser" -> Rabbit::Controllers::TestUser
|
|
9
|
+
class TestUser < BugBunny::Controller
|
|
10
|
+
# GET /show (Simulado)
|
|
11
|
+
# Usado por TestUser.find(1)
|
|
12
|
+
def show
|
|
13
|
+
puts " [API] 🔍 Buscando usuario ID: #{params[:id]}"
|
|
14
|
+
if params[:id].to_i == 999
|
|
15
|
+
# Simulamos un 404
|
|
16
|
+
render status: 404, json: { error: "User not found" }
|
|
17
|
+
else
|
|
18
|
+
render status: 200, json: {
|
|
19
|
+
id: params[:id].to_i,
|
|
20
|
+
name: "Gabriel",
|
|
21
|
+
email: "gabriel@test.com",
|
|
22
|
+
persisted: true
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# POST /create
|
|
28
|
+
# Usado por TestUser.create(...)
|
|
29
|
+
def create
|
|
30
|
+
puts " [API] 💾 Creando usuario: #{params.inspect}"
|
|
31
|
+
|
|
32
|
+
# Simulamos guardado
|
|
33
|
+
new_id = rand(1000..9999)
|
|
34
|
+
|
|
35
|
+
render status: 201, json: {
|
|
36
|
+
id: new_id,
|
|
37
|
+
name: params[:name],
|
|
38
|
+
email: params[:email],
|
|
39
|
+
created_at: Time.now
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Acción custom (RPC manual)
|
|
44
|
+
def ping
|
|
45
|
+
render status: 200, json: { message: "Pong!" }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
data/test_helper.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# test_helper.rb
|
|
2
|
+
require_relative 'lib/bug_bunny'
|
|
3
|
+
|
|
4
|
+
# Forzar flush de logs
|
|
5
|
+
$stdout.sync = true
|
|
6
|
+
|
|
7
|
+
BugBunny.configure do |config|
|
|
8
|
+
config.host = 'localhost'
|
|
9
|
+
config.username = 'wisproMQ'
|
|
10
|
+
config.password = 'wisproMQ'
|
|
11
|
+
config.vhost = 'sync.devel'
|
|
12
|
+
config.logger = Logger.new(STDOUT)
|
|
13
|
+
config.logger.level = Logger::WARN # Menos ruido, solo errores importantes
|
|
14
|
+
config.rpc_timeout = 5
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Pool compartido
|
|
18
|
+
TEST_POOL = ConnectionPool.new(size: 5, timeout: 5) do
|
|
19
|
+
BugBunny.create_connection
|
|
20
|
+
end
|
data/test_resource.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require_relative 'test_helper'
|
|
2
|
+
|
|
3
|
+
class TestUser < BugBunny::Resource
|
|
4
|
+
# Se decide qué pool usar en cada petición
|
|
5
|
+
self.connection_pool = -> {
|
|
6
|
+
nil || TEST_POOL
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
# El exchange cambia según el entorno
|
|
10
|
+
self.exchange = -> {
|
|
11
|
+
ENV['IS_STAGING'] ? 'test_exchange' : 'test_exchange'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
self.exchange_type = 'topic'
|
|
15
|
+
self.routing_key_prefix = 'test_user'
|
|
16
|
+
|
|
17
|
+
attribute :id, :integer
|
|
18
|
+
attribute :name, :string
|
|
19
|
+
attribute :email, :string
|
|
20
|
+
|
|
21
|
+
validates :name, presence: true
|
|
22
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bug_bunny
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- gabix
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-02-05 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: bunny
|
|
@@ -23,6 +24,160 @@ dependencies:
|
|
|
23
24
|
- - "~>"
|
|
24
25
|
- !ruby/object:Gem::Version
|
|
25
26
|
version: '2.24'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: connection_pool
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.4'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.4'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: concurrent-ruby
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.3'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.3'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: activemodel
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '6.1'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '6.1'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: activesupport
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '6.1'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '6.1'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rack
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '2.0'
|
|
90
|
+
type: :runtime
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '2.0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: json
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :runtime
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: ostruct
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :runtime
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: bundler
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: rake
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: rspec
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - ">="
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '0'
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - ">="
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '0'
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: yard
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - ">="
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '0'
|
|
174
|
+
type: :development
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - ">="
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: '0'
|
|
26
181
|
description: Gem for sync and async comunication via rabbit bunny.
|
|
27
182
|
email:
|
|
28
183
|
- gab.edera@gmail.com
|
|
@@ -33,15 +188,32 @@ files:
|
|
|
33
188
|
- CHANGELOG.md
|
|
34
189
|
- README.md
|
|
35
190
|
- Rakefile
|
|
191
|
+
- bin_client.rb
|
|
192
|
+
- bin_suite.rb
|
|
193
|
+
- bin_worker.rb
|
|
194
|
+
- initializer_example.rb
|
|
36
195
|
- lib/bug_bunny.rb
|
|
196
|
+
- lib/bug_bunny/client.rb
|
|
37
197
|
- lib/bug_bunny/config.rb
|
|
198
|
+
- lib/bug_bunny/consumer.rb
|
|
38
199
|
- lib/bug_bunny/controller.rb
|
|
39
200
|
- lib/bug_bunny/exception.rb
|
|
40
|
-
- lib/bug_bunny/
|
|
201
|
+
- lib/bug_bunny/middleware/json_response.rb
|
|
202
|
+
- lib/bug_bunny/middleware/raise_error.rb
|
|
203
|
+
- lib/bug_bunny/middleware/stack.rb
|
|
204
|
+
- lib/bug_bunny/producer.rb
|
|
41
205
|
- lib/bug_bunny/rabbit.rb
|
|
206
|
+
- lib/bug_bunny/railtie.rb
|
|
207
|
+
- lib/bug_bunny/request.rb
|
|
42
208
|
- lib/bug_bunny/resource.rb
|
|
209
|
+
- lib/bug_bunny/session.rb
|
|
43
210
|
- lib/bug_bunny/version.rb
|
|
211
|
+
- lib/generators/bug_bunny/install/install_generator.rb
|
|
212
|
+
- lib/generators/bug_bunny/install/templates/initializer.rb
|
|
44
213
|
- sig/bug_bunny.rbs
|
|
214
|
+
- test_controller.rb
|
|
215
|
+
- test_helper.rb
|
|
216
|
+
- test_resource.rb
|
|
45
217
|
homepage: https://github.com/gedera/bug_bunny
|
|
46
218
|
licenses:
|
|
47
219
|
- MIT
|
|
@@ -49,6 +221,7 @@ metadata:
|
|
|
49
221
|
homepage_uri: https://github.com/gedera/bug_bunny
|
|
50
222
|
source_code_uri: https://github.com/gedera/bug_bunny
|
|
51
223
|
changelog_uri: https://github.com/gedera/bug_bunny/blob/main/CHANGELOG.md
|
|
224
|
+
post_install_message:
|
|
52
225
|
rdoc_options: []
|
|
53
226
|
require_paths:
|
|
54
227
|
- lib
|
|
@@ -63,7 +236,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
63
236
|
- !ruby/object:Gem::Version
|
|
64
237
|
version: '0'
|
|
65
238
|
requirements: []
|
|
66
|
-
rubygems_version: 3.
|
|
239
|
+
rubygems_version: 3.4.19
|
|
240
|
+
signing_key:
|
|
67
241
|
specification_version: 4
|
|
68
242
|
summary: Gem for sync and async comunication via rabbit bunny.
|
|
69
243
|
test_files: []
|
data/lib/bug_bunny/publisher.rb
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
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 :connection
|
|
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
|
-
attribute :type, :string
|
|
70
|
-
attribute :action, :string
|
|
71
|
-
|
|
72
|
-
def publish!
|
|
73
|
-
app = Rabbit.new(connection: connection)
|
|
74
|
-
app.build_exchange(name: exchange_name, type: exchange_type)
|
|
75
|
-
app.publish!(message, publish_opts)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def publish_and_consume!
|
|
79
|
-
app = Rabbit.new(connection: connection)
|
|
80
|
-
app.build_exchange(name: exchange_name, type: exchange_type)
|
|
81
|
-
app.publish_and_consume!(message, publish_opts)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def publish_opts
|
|
85
|
-
{ routing_key: routing_key,
|
|
86
|
-
type: type,
|
|
87
|
-
persistent: persistent,
|
|
88
|
-
content_type: content_type,
|
|
89
|
-
content_encoding: content_encoding,
|
|
90
|
-
correlation_id: correlation_id,
|
|
91
|
-
reply_to: reply_to,
|
|
92
|
-
app_id: app_id,
|
|
93
|
-
headers: headers,
|
|
94
|
-
timestamp: timestamp,
|
|
95
|
-
expiration: expiration }
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def initialize(attrs = {})
|
|
99
|
-
super(attrs)
|
|
100
|
-
if attrs[:action].present?
|
|
101
|
-
args = attrs[:arguments] || {}
|
|
102
|
-
|
|
103
|
-
self.type = format(attrs[:action], args)
|
|
104
|
-
end
|
|
105
|
-
self.routing_key ||= self.class::ROUTING_KEY
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|