nats_messaging 1.5.1 → 1.6.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/lib/nats_messaging/nats_service.rb +70 -9
- data/lib/nats_messaging.rb +22 -3
- metadata +60 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: afa8e0bfe4f5c00bd91323e60c3d3e630bf1eea504495a079c667533fa98ca5a
|
|
4
|
+
data.tar.gz: 30a30e95c8c0feaabfaf01346faddedeeea6232e97f768ed58ddde810ea6285e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 862f641b1555417327a7d16c7a566d43b3ed168f5cf4403ad5732e8ef7e6eba6530fbae98a530c0a73fc615b65bda4b31dc08efec34ab437bc48cc41774062d2
|
|
7
|
+
data.tar.gz: f700b68ecae1504dc079c6702bddb4d1720c779101f0de0c9595aafc6134610fc5754c977e4b95bc48fb7348415620c860ffa074dc5dafc00841d394d265a75e
|
|
@@ -1,21 +1,82 @@
|
|
|
1
1
|
require 'nats/io/client'
|
|
2
2
|
require 'msgpack'
|
|
3
|
+
require 'logger'
|
|
4
|
+
require 'active_support'
|
|
5
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
|
6
|
+
require 'timeout'
|
|
3
7
|
|
|
4
8
|
module NatsMessaging
|
|
5
9
|
class NatsService
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
# Reintentos infinitos: con un solo server en el pool, agotar los intentos
|
|
11
|
+
# deja el proceso sin NATS hasta un reinicio manual. ping_interval más corto
|
|
12
|
+
# detecta conexiones zombie en ~1 min en vez de los ~4 min por defecto.
|
|
13
|
+
DEFAULT_CONNECT_OPTIONS = {
|
|
14
|
+
reconnect: true,
|
|
15
|
+
max_reconnect_attempts: -1,
|
|
16
|
+
reconnect_time_wait: 30,
|
|
17
|
+
ping_interval: 30,
|
|
18
|
+
max_outstanding_pings: 2
|
|
19
|
+
}.freeze
|
|
20
|
+
|
|
21
|
+
# nats-pure usa el mismo max_reconnect_attempts tanto para el connect
|
|
22
|
+
# inicial (establish_connection!) como para la reconexión de una conexión
|
|
23
|
+
# ya establecida (attempt_reconnect): con max_reconnect_attempts: -1,
|
|
24
|
+
# can_reuse_server? siempre devuelve true y el connect inicial reintenta
|
|
25
|
+
# para siempre sin lanzar excepción, colgando el arranque del proceso host.
|
|
26
|
+
# El `connect_timeout` propio de nats-pure no sirve para acotar esto: solo
|
|
27
|
+
# limita un intento de conexión TCP/handshake individual, no la cantidad
|
|
28
|
+
# de reintentos. No hay forma nativa en nats-pure 2.5 de distinguir
|
|
29
|
+
# "primer connect" de "reconexión posterior", así que se acota el connect
|
|
30
|
+
# inicial desde afuera con Timeout.timeout. Es aceptable usar Timeout pese
|
|
31
|
+
# a su conocida rudeza (mata el hilo sin dar chance de cleanup) porque
|
|
32
|
+
# ocurre solo durante el boot, antes de que exista estado que corromper;
|
|
33
|
+
# si el timeout dispara, la instancia parcialmente construida simplemente
|
|
34
|
+
# se descarta al propagar la excepción.
|
|
35
|
+
DEFAULT_INITIAL_CONNECT_TIMEOUT = 15
|
|
36
|
+
|
|
37
|
+
attr_reader :pid
|
|
38
|
+
|
|
39
|
+
def initialize(nats_url, stream_name: nil, subjects: [], connect_options: {}, initial_connect_timeout: DEFAULT_INITIAL_CONNECT_TIMEOUT)
|
|
40
|
+
@pid = Process.pid
|
|
41
|
+
@subscriptions = {} # Store active subscriptions
|
|
42
|
+
begin
|
|
43
|
+
@nats = Timeout.timeout(initial_connect_timeout) do
|
|
44
|
+
NATS.connect(nats_url, DEFAULT_CONNECT_OPTIONS.merge(connect_options))
|
|
45
|
+
end
|
|
46
|
+
rescue Timeout::Error
|
|
47
|
+
raise NatsMessaging::InitialConnectTimeoutError,
|
|
48
|
+
"Could not connect to NATS at #{nats_url} within #{initial_connect_timeout}s"
|
|
49
|
+
end
|
|
50
|
+
register_lifecycle_callbacks
|
|
8
51
|
if stream_name
|
|
9
52
|
@js = @nats.jetstream
|
|
10
53
|
create_stream(stream_name, subjects)
|
|
11
54
|
end
|
|
12
|
-
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def logger
|
|
58
|
+
@logger ||= (defined?(Rails) && Rails.logger) || Logger.new(STDOUT)
|
|
13
59
|
end
|
|
14
60
|
|
|
15
61
|
def log_duration(start_time, message_format, *args)
|
|
16
62
|
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
17
63
|
full_message = "NATS [%.2fs]: #{message_format}" % [duration, *args]
|
|
18
|
-
|
|
64
|
+
logger.info full_message
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def register_lifecycle_callbacks
|
|
68
|
+
@nats.on_disconnect do |e|
|
|
69
|
+
logger.warn "NATS: disconnected#{e ? " (#{e.message})" : ''}"
|
|
70
|
+
end
|
|
71
|
+
@nats.on_reconnect do
|
|
72
|
+
logger.info "NATS: reconnected to #{@nats.connected_server}"
|
|
73
|
+
end
|
|
74
|
+
@nats.on_error do |e|
|
|
75
|
+
logger.error "NATS: error: #{e.message}"
|
|
76
|
+
end
|
|
77
|
+
@nats.on_close do
|
|
78
|
+
logger.error "NATS: connection CLOSED permanently"
|
|
79
|
+
end
|
|
19
80
|
end
|
|
20
81
|
|
|
21
82
|
# Create a stream
|
|
@@ -67,7 +128,7 @@ module NatsMessaging
|
|
|
67
128
|
|
|
68
129
|
# Subscribe to a subject using MessagePack
|
|
69
130
|
def subscribe_to_subject(subject, durable_name = "durable_name")
|
|
70
|
-
|
|
131
|
+
logger.info "NATS: Subscribing to #{subject}"
|
|
71
132
|
if @js
|
|
72
133
|
@subscriptions[subject] = @js.subscribe(subject, durable: durable_name) do |msg|
|
|
73
134
|
unpacked_data = process_received_message(msg, subject)
|
|
@@ -99,7 +160,7 @@ module NatsMessaging
|
|
|
99
160
|
|
|
100
161
|
# Send a request to a subject and wait for response using MessagePack
|
|
101
162
|
def send_request(subject, message, timeout = 5)
|
|
102
|
-
|
|
163
|
+
logger.info "NATS: Sending request to #{subject} with message: #{message}"
|
|
103
164
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
104
165
|
begin
|
|
105
166
|
packed_message = message.to_msgpack # Serializar el mensaje
|
|
@@ -126,13 +187,13 @@ module NatsMessaging
|
|
|
126
187
|
end
|
|
127
188
|
begin
|
|
128
189
|
# Create a new subscription
|
|
129
|
-
|
|
190
|
+
logger.info "NATS: Listening on #{subject} with reply message: #{reply_message}"
|
|
130
191
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) # En caso de que falle antes del segundo begin
|
|
131
192
|
@subscriptions[subject] = @nats.subscribe(subject) do |msg|
|
|
132
193
|
begin
|
|
133
194
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
134
195
|
unpacked_data = MessagePack.unpack(msg.data) # Deserializar mensaje recibido
|
|
135
|
-
|
|
196
|
+
logger.info "NATS: Received request on #{subject}: #{unpacked_data}"
|
|
136
197
|
indifferent_unpacked_data = make_data_indifferent(unpacked_data)
|
|
137
198
|
yield_return = yield(subject, indifferent_unpacked_data) if block_given?
|
|
138
199
|
reply = reply_message.nil? ? yield_return : reply_message
|
|
@@ -147,7 +208,7 @@ module NatsMessaging
|
|
|
147
208
|
indifferent_unpacked_data
|
|
148
209
|
rescue => e
|
|
149
210
|
log_duration(start_time, "Error while processing message on %s: %s", subject, e.message)
|
|
150
|
-
|
|
211
|
+
logger.error e.backtrace.join("\n")
|
|
151
212
|
end
|
|
152
213
|
end
|
|
153
214
|
rescue => e
|
data/lib/nats_messaging.rb
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
require 'nats_messaging/nats_service'
|
|
2
2
|
|
|
3
3
|
module NatsMessaging
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
# Se lanza cuando el connect inicial no logra establecerse dentro de
|
|
5
|
+
# initial_connect_timeout segundos. No debe confundirse con las
|
|
6
|
+
# desconexiones posteriores a una conexión ya establecida, que nats-pure
|
|
7
|
+
# reintenta indefinidamente en su propio hilo sin lanzar excepciones.
|
|
8
|
+
class InitialConnectTimeoutError < StandardError; end
|
|
9
|
+
|
|
10
|
+
# Main entry point to expose the functionalities.
|
|
11
|
+
#
|
|
12
|
+
# Memoiza la instancia por PID: si el proceso actual forkeó (Puma/solid_queue)
|
|
13
|
+
# después de que @service ya existía, la conexión heredada es inválida (el
|
|
14
|
+
# socket pertenece al padre) y se descarta sin intentar cerrarla, creando una
|
|
15
|
+
# instancia nueva con los parámetros de ESTA llamada. Dentro del mismo PID la
|
|
16
|
+
# memoización ignora los parámetros de llamadas posteriores, igual que antes.
|
|
17
|
+
def self.service(nats_url, stream_name: nil, subjects: [], connect_options: {}, initial_connect_timeout: NatsService::DEFAULT_INITIAL_CONNECT_TIMEOUT)
|
|
18
|
+
@service = nil if @service && @service.pid != Process.pid
|
|
19
|
+
@service ||= NatsService.new(
|
|
20
|
+
nats_url,
|
|
21
|
+
stream_name: stream_name,
|
|
22
|
+
subjects: subjects,
|
|
23
|
+
connect_options: connect_options,
|
|
24
|
+
initial_connect_timeout: initial_connect_timeout
|
|
25
|
+
)
|
|
7
26
|
end
|
|
8
27
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: nats_messaging
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bea Graboloza
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: nats-pure
|
|
@@ -24,6 +24,62 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '2.5'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: msgpack
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.2'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.2'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: logger
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.7'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.7'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: activesupport
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '6.0'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '6.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rspec
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '3.0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '3.0'
|
|
27
83
|
description: A service to send and receive messages on a Rails application using NATS
|
|
28
84
|
email: beatriz.graboloza@bpo-advisors.net
|
|
29
85
|
executables: []
|
|
@@ -44,14 +100,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
44
100
|
requirements:
|
|
45
101
|
- - ">="
|
|
46
102
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '0'
|
|
103
|
+
version: '3.0'
|
|
48
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
105
|
requirements:
|
|
50
106
|
- - ">="
|
|
51
107
|
- !ruby/object:Gem::Version
|
|
52
108
|
version: '0'
|
|
53
109
|
requirements: []
|
|
54
|
-
rubygems_version: 3.
|
|
110
|
+
rubygems_version: 3.5.16
|
|
55
111
|
signing_key:
|
|
56
112
|
specification_version: 4
|
|
57
113
|
summary: a NATS service for messaging
|