nats_messaging 1.5.1 → 1.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78d691503ace2b93a46a4e9f501ead1885404063abbe88d7883e59bcb7ed1fe0
4
- data.tar.gz: f9d2c4178caab4acbb383e39cb6e097044a0ab53f48bb7b1f0f3d05470188e63
3
+ metadata.gz: 29004a0c5885d2492ffef134f17af546250d9b24aa6d24bef5410a9dbff5e014
4
+ data.tar.gz: a6c1b23843eed5f8391ee1e4f6acbd8274089e3066884c1d5adbfd7a2877e76b
5
5
  SHA512:
6
- metadata.gz: d6053bbcfd6ca775166c61e55f7cf79395768ea840ab72f1763fb0c078e6c2118a99de35f68214c2bec0f74095dd87db7380f4ef0767c4b80fc4410a75697489
7
- data.tar.gz: 13a429b538791a448782c6264746b3a0ab63842914de2eb7b7387ef3bc550ccb36d391fcea81d520fd734f0beac647be75442d14da38ffe926af13105235182f
6
+ metadata.gz: f1ce4f99c59a8e24daef41297201809092350b33631cbfafebf70d703a83fdc9c84bb60d15e545bd2da890910eb97cd4897536664d3a1886c98d9e9266c1b464
7
+ data.tar.gz: af5310ce484fcfd98bf497378fa8bfbe018379f211fa8909fe9366866ed82fc31792641afc5f509c40b731ad3071e68b33a67d7402a1c052c2643335a2cdc61f
@@ -1,21 +1,58 @@
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'
3
6
 
4
7
  module NatsMessaging
5
8
  class NatsService
6
- def initialize(nats_url, stream_name: nil, subjects: [])
7
- @nats = NATS.connect(nats_url)
9
+ # Reintentos infinitos: con un solo server en el pool, agotar los intentos
10
+ # deja el proceso sin NATS hasta un reinicio manual. ping_interval más corto
11
+ # detecta conexiones zombie en ~1 min en vez de los ~4 min por defecto.
12
+ DEFAULT_CONNECT_OPTIONS = {
13
+ reconnect: true,
14
+ max_reconnect_attempts: -1,
15
+ reconnect_time_wait: 30,
16
+ ping_interval: 30,
17
+ max_outstanding_pings: 2
18
+ }.freeze
19
+
20
+ attr_reader :pid
21
+
22
+ def initialize(nats_url, stream_name: nil, subjects: [], connect_options: {})
23
+ @pid = Process.pid
24
+ @subscriptions = {} # Store active subscriptions
25
+ @nats = NATS.connect(nats_url, DEFAULT_CONNECT_OPTIONS.merge(connect_options))
26
+ register_lifecycle_callbacks
8
27
  if stream_name
9
28
  @js = @nats.jetstream
10
29
  create_stream(stream_name, subjects)
11
30
  end
12
- @subscriptions = {} # Store active subscriptions
31
+ end
32
+
33
+ def logger
34
+ @logger ||= (defined?(Rails) && Rails.logger) || Logger.new(STDOUT)
13
35
  end
14
36
 
15
37
  def log_duration(start_time, message_format, *args)
16
38
  duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
17
39
  full_message = "NATS [%.2fs]: #{message_format}" % [duration, *args]
18
- Rails.logger.info full_message
40
+ logger.info full_message
41
+ end
42
+
43
+ def register_lifecycle_callbacks
44
+ @nats.on_disconnect do |e|
45
+ logger.warn "NATS: disconnected#{e ? " (#{e.message})" : ''}"
46
+ end
47
+ @nats.on_reconnect do
48
+ logger.info "NATS: reconnected to #{@nats.connected_server}"
49
+ end
50
+ @nats.on_error do |e|
51
+ logger.error "NATS: error: #{e.message}"
52
+ end
53
+ @nats.on_close do
54
+ logger.error "NATS: connection CLOSED permanently"
55
+ end
19
56
  end
20
57
 
21
58
  # Create a stream
@@ -67,7 +104,7 @@ module NatsMessaging
67
104
 
68
105
  # Subscribe to a subject using MessagePack
69
106
  def subscribe_to_subject(subject, durable_name = "durable_name")
70
- Rails.logger.info "NATS: Subscribing to #{subject}"
107
+ logger.info "NATS: Subscribing to #{subject}"
71
108
  if @js
72
109
  @subscriptions[subject] = @js.subscribe(subject, durable: durable_name) do |msg|
73
110
  unpacked_data = process_received_message(msg, subject)
@@ -99,7 +136,7 @@ module NatsMessaging
99
136
 
100
137
  # Send a request to a subject and wait for response using MessagePack
101
138
  def send_request(subject, message, timeout = 5)
102
- Rails.logger.info "NATS: Sending request to #{subject} with message: #{message}"
139
+ logger.info "NATS: Sending request to #{subject} with message: #{message}"
103
140
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
104
141
  begin
105
142
  packed_message = message.to_msgpack # Serializar el mensaje
@@ -126,13 +163,13 @@ module NatsMessaging
126
163
  end
127
164
  begin
128
165
  # Create a new subscription
129
- Rails.logger.info "NATS: Listening on #{subject} with reply message: #{reply_message}"
166
+ logger.info "NATS: Listening on #{subject} with reply message: #{reply_message}"
130
167
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) # En caso de que falle antes del segundo begin
131
168
  @subscriptions[subject] = @nats.subscribe(subject) do |msg|
132
169
  begin
133
170
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
134
171
  unpacked_data = MessagePack.unpack(msg.data) # Deserializar mensaje recibido
135
- Rails.logger.info "NATS: Received request on #{subject}: #{unpacked_data}"
172
+ logger.info "NATS: Received request on #{subject}: #{unpacked_data}"
136
173
  indifferent_unpacked_data = make_data_indifferent(unpacked_data)
137
174
  yield_return = yield(subject, indifferent_unpacked_data) if block_given?
138
175
  reply = reply_message.nil? ? yield_return : reply_message
@@ -147,7 +184,7 @@ module NatsMessaging
147
184
  indifferent_unpacked_data
148
185
  rescue => e
149
186
  log_duration(start_time, "Error while processing message on %s: %s", subject, e.message)
150
- Rails.logger.error e.backtrace.join("\n")
187
+ logger.error e.backtrace.join("\n")
151
188
  end
152
189
  end
153
190
  rescue => e
@@ -1,8 +1,20 @@
1
1
  require 'nats_messaging/nats_service'
2
2
 
3
3
  module NatsMessaging
4
- # Main entry point to expose the functionalities
5
- def self.service(nats_url, stream_name: nil, subjects: [])
6
- @service ||= NatsService.new(nats_url, stream_name: stream_name, subjects: subjects)
4
+ # Main entry point to expose the functionalities.
5
+ #
6
+ # Memoiza la instancia por PID: si el proceso actual forkeó (Puma/solid_queue)
7
+ # después de que @service ya existía, la conexión heredada es inválida (el
8
+ # socket pertenece al padre) y se descarta sin intentar cerrarla, creando una
9
+ # instancia nueva con los parámetros de ESTA llamada. Dentro del mismo PID la
10
+ # memoización ignora los parámetros de llamadas posteriores, igual que antes.
11
+ def self.service(nats_url, stream_name: nil, subjects: [], connect_options: {})
12
+ @service = nil if @service && @service.pid != Process.pid
13
+ @service ||= NatsService.new(
14
+ nats_url,
15
+ stream_name: stream_name,
16
+ subjects: subjects,
17
+ connect_options: connect_options
18
+ )
7
19
  end
8
20
  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.5.1
4
+ version: 1.6.0
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-04-08 00:00:00.000000000 Z
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.0.9
110
+ rubygems_version: 3.5.16
55
111
  signing_key:
56
112
  specification_version: 4
57
113
  summary: a NATS service for messaging