nats_wave 1.1.8 → 1.1.9
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/Gemfile.lock +1 -1
- data/lib/nats_wave/active_record_extension.rb +93 -0
- data/lib/nats_wave/adapters/active_record.rb +207 -0
- data/lib/nats_wave/adapters/datadog_metrics.rb +1 -1
- data/lib/nats_wave/client.rb +411 -154
- data/lib/nats_wave/concerns/mappable.rb +481 -117
- data/lib/nats_wave/configuration.rb +1 -1
- data/lib/nats_wave/database_connector.rb +51 -0
- data/lib/nats_wave/publisher.rb +142 -39
- data/lib/nats_wave/railtie.rb +126 -6
- data/lib/nats_wave/subscriber.rb +391 -1
- data/lib/nats_wave/version.rb +1 -1
- data/lib/nats_wave.rb +99 -0
- metadata +3 -3
- data/lib/nats_wave/concerns/publishable.rb +0 -216
data/lib/nats_wave/client.rb
CHANGED
@@ -1,3 +1,154 @@
|
|
1
|
+
# # # # # frozen_string_literal: true
|
2
|
+
# # # #
|
3
|
+
# # # # module NatsWave
|
4
|
+
# # # # class Client
|
5
|
+
# # # # attr_reader :config, :publisher, :subscriber, :client
|
6
|
+
# # # #
|
7
|
+
# # # # def initialize(options = {})
|
8
|
+
# # # # @config = Configuration.new(options)
|
9
|
+
# # # # @client = nil
|
10
|
+
# # # # @publisher = nil
|
11
|
+
# # # # @subscriber = nil
|
12
|
+
# # # # @middleware_stack = []
|
13
|
+
# # # #
|
14
|
+
# # # # setup_connection_pool
|
15
|
+
# # # # setup_middleware
|
16
|
+
# # # # establish_connections
|
17
|
+
# # # # end
|
18
|
+
# # # #
|
19
|
+
# # # # def publish(subject:, model:, action:, data:, metadata: {})
|
20
|
+
# # # # ensure_connected!
|
21
|
+
# # # # @publisher.publish(
|
22
|
+
# # # # subject: subject,
|
23
|
+
# # # # model: model,
|
24
|
+
# # # # action: action,
|
25
|
+
# # # # data: data,
|
26
|
+
# # # # metadata: metadata
|
27
|
+
# # # # )
|
28
|
+
# # # # end
|
29
|
+
# # # #
|
30
|
+
# # # # def publish_batch(events)
|
31
|
+
# # # # ensure_connected!
|
32
|
+
# # # # @publisher.publish_batch(events)
|
33
|
+
# # # # end
|
34
|
+
# # # #
|
35
|
+
# # # # def subscribe(subjects:, model_mappings: {}, &block)
|
36
|
+
# # # # NatsWave.logger.info "Ensuring connection..."
|
37
|
+
# # # # ensure_connected!
|
38
|
+
# # # # raise "Subscriber not initialized" unless @subscriber
|
39
|
+
# # # #
|
40
|
+
# # # # NatsWave.logger.info "Subscribing to subjects: #{subjects.inspect}"
|
41
|
+
# # # # NatsWave.logger.info "Subscribing with model mapping: #{model_mappings.inspect}"
|
42
|
+
# # # # # puts "Subscribing to subjects: #{subjects.inspect}"
|
43
|
+
# # # # @subscriber.listen(
|
44
|
+
# # # # subjects: subjects,
|
45
|
+
# # # # model_mappings: model_mappings,
|
46
|
+
# # # # &block
|
47
|
+
# # # # )
|
48
|
+
# # # # end
|
49
|
+
# # # #
|
50
|
+
# # # #
|
51
|
+
# # # # def start_subscriber
|
52
|
+
# # # # ensure_connected!
|
53
|
+
# # # # @subscriber.begin if @subscriber
|
54
|
+
# # # # end
|
55
|
+
# # # #
|
56
|
+
# # # # def health_check
|
57
|
+
# # # # {
|
58
|
+
# # # # nats_connected: connected?,
|
59
|
+
# # # # database_connected: database_connected?,
|
60
|
+
# # # # nats_url: @config.nats_url,
|
61
|
+
# # # # nats_server_url: @config.nats_server_url,
|
62
|
+
# # # # service_name: @config.service_name,
|
63
|
+
# # # # version: @config.version,
|
64
|
+
# # # # instance_id: @config.instance_id,
|
65
|
+
# # # # published_subjects: @config.subject_patterns,
|
66
|
+
# # # # timestamp: Time.current.iso8601,
|
67
|
+
# # # # }
|
68
|
+
# # # # end
|
69
|
+
# # # #
|
70
|
+
# # # # def connected?
|
71
|
+
# # # # @client && @client.connected?
|
72
|
+
# # # # end
|
73
|
+
# # # #
|
74
|
+
# # # # def disconnect!
|
75
|
+
# # # # @subscriber&.reset
|
76
|
+
# # # # @client&.close
|
77
|
+
# # # # @connection_pool&.shutdown
|
78
|
+
# # # # @connection_pool&.wait_for_termination(5)
|
79
|
+
# # # # end
|
80
|
+
# # # #
|
81
|
+
# # # # private
|
82
|
+
# # # #
|
83
|
+
# # # # def setup_connection_pool
|
84
|
+
# # # # return unless defined?(Concurrent)
|
85
|
+
# # # #
|
86
|
+
# # # # @connection_pool = Concurrent::ThreadPoolExecutor.new(
|
87
|
+
# # # # min_threads: 5,
|
88
|
+
# # # # max_threads: @config.connection_pool_size
|
89
|
+
# # # # )
|
90
|
+
# # # # end
|
91
|
+
# # # #
|
92
|
+
# # # # def setup_middleware
|
93
|
+
# # # # @middleware_stack = []
|
94
|
+
# # # #
|
95
|
+
# # # # if @config.middleware_authentication_enabled
|
96
|
+
# # # # @middleware_stack << Middleware::Authentication.new(@config)
|
97
|
+
# # # # end
|
98
|
+
# # # #
|
99
|
+
# # # # if @config.middleware_validation_enabled
|
100
|
+
# # # # @middleware_stack << Middleware::Validation.new(@config)
|
101
|
+
# # # # end
|
102
|
+
# # # #
|
103
|
+
# # # # if @config.middleware_logging_enabled
|
104
|
+
# # # # @middleware_stack << Middleware::Logging.new(@config)
|
105
|
+
# # # # end
|
106
|
+
# # # # end
|
107
|
+
# # # #
|
108
|
+
# # # # def establish_connections
|
109
|
+
# # # # return unless nats_available?
|
110
|
+
# # # #
|
111
|
+
# # # # establish_nats_connection
|
112
|
+
# # # #
|
113
|
+
# # # # if @config.publishing_enabled
|
114
|
+
# # # # @publisher = Publisher.new(@config, @client, @middleware_stack)
|
115
|
+
# # # # end
|
116
|
+
# # # #
|
117
|
+
# # # # if @config.subscription_enabled
|
118
|
+
# # # # @subscriber = Subscriber.new(@config, @client, @middleware_stack)
|
119
|
+
# # # # end
|
120
|
+
# # # # end
|
121
|
+
# # # #
|
122
|
+
# # # # def establish_nats_connection
|
123
|
+
# # # # @client = NATS.connect(
|
124
|
+
# # # # @config.nats_url,
|
125
|
+
# # # # reconnect_time_wait: @config.retry_delay,
|
126
|
+
# # # # max_reconnect_attempts: @config.reconnect_attempts
|
127
|
+
# # # # )
|
128
|
+
# # # # NatsWave.logger.info("Connected to NATS at #{@config.nats_url}")
|
129
|
+
# # # # rescue => e
|
130
|
+
# # # # NatsWave.logger.error("Failed to connect to NATS: #{e.message}")
|
131
|
+
# # # # raise ConnectionError, "Failed to connect to NATS: #{e.message}"
|
132
|
+
# # # # end
|
133
|
+
# # # #
|
134
|
+
# # # # def ensure_connected!
|
135
|
+
# # # # raise ConnectionError, "Not connected to NATS" unless connected?
|
136
|
+
# # # # end
|
137
|
+
# # # #
|
138
|
+
# # # # def database_connected?
|
139
|
+
# # # # return false unless @subscriber
|
140
|
+
# # # # @subscriber.database_connected?
|
141
|
+
# # # # end
|
142
|
+
# # # #
|
143
|
+
# # # # def nats_available?
|
144
|
+
# # # # defined?(NATS)
|
145
|
+
# # # # rescue LoadError
|
146
|
+
# # # # false
|
147
|
+
# # # # end
|
148
|
+
# # # # end
|
149
|
+
# # # # end
|
150
|
+
# # #
|
151
|
+
# # #
|
1
152
|
# # # # frozen_string_literal: true
|
2
153
|
# # #
|
3
154
|
# # # module NatsWave
|
@@ -10,76 +161,64 @@
|
|
10
161
|
# # # @publisher = nil
|
11
162
|
# # # @subscriber = nil
|
12
163
|
# # # @middleware_stack = []
|
164
|
+
# # # @shutdown = false
|
13
165
|
# # #
|
14
166
|
# # # setup_connection_pool
|
15
167
|
# # # setup_middleware
|
16
168
|
# # # establish_connections
|
169
|
+
# # # setup_signal_handlers
|
17
170
|
# # # end
|
18
171
|
# # #
|
19
|
-
# # # def publish(subject:, model:, action:, data:, metadata: {})
|
20
|
-
# # # ensure_connected!
|
21
|
-
# # # @publisher.publish(
|
22
|
-
# # # subject: subject,
|
23
|
-
# # # model: model,
|
24
|
-
# # # action: action,
|
25
|
-
# # # data: data,
|
26
|
-
# # # metadata: metadata
|
27
|
-
# # # )
|
28
|
-
# # # end
|
29
|
-
# # #
|
30
|
-
# # # def publish_batch(events)
|
31
|
-
# # # ensure_connected!
|
32
|
-
# # # @publisher.publish_batch(events)
|
33
|
-
# # # end
|
34
|
-
# # #
|
35
|
-
# # # def subscribe(subjects:, model_mappings: {}, &block)
|
36
|
-
# # # NatsWave.logger.info "Ensuring connection..."
|
37
|
-
# # # ensure_connected!
|
38
|
-
# # # raise "Subscriber not initialized" unless @subscriber
|
39
|
-
# # #
|
40
|
-
# # # NatsWave.logger.info "Subscribing to subjects: #{subjects.inspect}"
|
41
|
-
# # # NatsWave.logger.info "Subscribing with model mapping: #{model_mappings.inspect}"
|
42
|
-
# # # # puts "Subscribing to subjects: #{subjects.inspect}"
|
43
|
-
# # # @subscriber.listen(
|
44
|
-
# # # subjects: subjects,
|
45
|
-
# # # model_mappings: model_mappings,
|
46
|
-
# # # &block
|
47
|
-
# # # )
|
48
|
-
# # # end
|
49
|
-
# # #
|
50
|
-
# # #
|
51
172
|
# # # def start_subscriber
|
52
173
|
# # # ensure_connected!
|
53
|
-
# # #
|
54
|
-
# # # end
|
174
|
+
# # # return unless @subscriber
|
55
175
|
# # #
|
56
|
-
# # #
|
57
|
-
# # # {
|
58
|
-
# # # nats_connected: connected?,
|
59
|
-
# # # database_connected: database_connected?,
|
60
|
-
# # # nats_url: @config.nats_url,
|
61
|
-
# # # nats_server_url: @config.nats_server_url,
|
62
|
-
# # # service_name: @config.service_name,
|
63
|
-
# # # version: @config.version,
|
64
|
-
# # # instance_id: @config.instance_id,
|
65
|
-
# # # published_subjects: @config.subject_patterns,
|
66
|
-
# # # timestamp: Time.current.iso8601,
|
67
|
-
# # # }
|
68
|
-
# # # end
|
176
|
+
# # # @subscriber.begin
|
69
177
|
# # #
|
70
|
-
# # #
|
71
|
-
# # #
|
178
|
+
# # # # Keep the main thread alive in console/rake tasks
|
179
|
+
# # # if defined?(Rails::Console) || $PROGRAM_NAME.include?('rake')
|
180
|
+
# # # keep_main_thread_alive
|
181
|
+
# # # end
|
72
182
|
# # # end
|
73
183
|
# # #
|
74
184
|
# # # def disconnect!
|
185
|
+
# # # @shutdown = true
|
186
|
+
# # #
|
187
|
+
# # # NatsWave.logger.info "🛑 Shutting down NatsWave client..."
|
188
|
+
# # #
|
75
189
|
# # # @subscriber&.reset
|
76
|
-
# # # @client&.close
|
190
|
+
# # # @client&.close if @client&.connected?
|
77
191
|
# # # @connection_pool&.shutdown
|
78
192
|
# # # @connection_pool&.wait_for_termination(5)
|
193
|
+
# # #
|
194
|
+
# # # NatsWave.logger.info "✅ NatsWave client shutdown complete"
|
79
195
|
# # # end
|
80
196
|
# # #
|
81
197
|
# # # private
|
82
198
|
# # #
|
199
|
+
# # # def setup_signal_handlers
|
200
|
+
# # # # Handle graceful shutdown
|
201
|
+
# # # ['INT', 'TERM'].each do |signal|
|
202
|
+
# # # Signal.trap(signal) do
|
203
|
+
# # # NatsWave.logger.info "🛑 Received #{signal}, shutting down gracefully..."
|
204
|
+
# # # disconnect!
|
205
|
+
# # # exit(0)
|
206
|
+
# # # end
|
207
|
+
# # # end
|
208
|
+
# # # end
|
209
|
+
# # #
|
210
|
+
# # # def keep_main_thread_alive
|
211
|
+
# # # # This prevents the main thread from exiting in console/rake tasks
|
212
|
+
# # # Thread.new do
|
213
|
+
# # # while !@shutdown
|
214
|
+
# # # sleep 1
|
215
|
+
# # # end
|
216
|
+
# # # end.join
|
217
|
+
# # # rescue Interrupt
|
218
|
+
# # # NatsWave.logger.info "🛑 Interrupted, shutting down..."
|
219
|
+
# # # disconnect!
|
220
|
+
# # # end
|
221
|
+
# # #
|
83
222
|
# # # def setup_connection_pool
|
84
223
|
# # # return unless defined?(Concurrent)
|
85
224
|
# # #
|
@@ -148,7 +287,6 @@
|
|
148
287
|
# # # end
|
149
288
|
# # # end
|
150
289
|
# #
|
151
|
-
# #
|
152
290
|
# # # frozen_string_literal: true
|
153
291
|
# #
|
154
292
|
# # module NatsWave
|
@@ -166,19 +304,61 @@
|
|
166
304
|
# # setup_connection_pool
|
167
305
|
# # setup_middleware
|
168
306
|
# # establish_connections
|
169
|
-
# #
|
307
|
+
# # end
|
308
|
+
# #
|
309
|
+
# # def publish(subject:, model:, action:, data:, metadata: {})
|
310
|
+
# # ensure_connected!
|
311
|
+
# # @publisher.publish(
|
312
|
+
# # subject: subject,
|
313
|
+
# # model: model,
|
314
|
+
# # action: action,
|
315
|
+
# # data: data,
|
316
|
+
# # metadata: metadata
|
317
|
+
# # )
|
318
|
+
# # end
|
319
|
+
# #
|
320
|
+
# # def publish_batch(events)
|
321
|
+
# # ensure_connected!
|
322
|
+
# # @publisher.publish_batch(events)
|
323
|
+
# # end
|
324
|
+
# #
|
325
|
+
# # def subscribe(subjects:, model_mappings: {}, &block)
|
326
|
+
# # NatsWave.logger.info "Ensuring connection..."
|
327
|
+
# # ensure_connected!
|
328
|
+
# # raise "Subscriber not initialized" unless @subscriber
|
329
|
+
# #
|
330
|
+
# # NatsWave.logger.info "Subscribing to subjects: #{subjects.inspect}"
|
331
|
+
# # NatsWave.logger.info "Subscribing with model mapping: #{model_mappings.inspect}"
|
332
|
+
# # @subscriber.listen(
|
333
|
+
# # subjects: subjects,
|
334
|
+
# # model_mappings: model_mappings,
|
335
|
+
# # &block
|
336
|
+
# # )
|
170
337
|
# # end
|
171
338
|
# #
|
172
339
|
# # def start_subscriber
|
173
340
|
# # ensure_connected!
|
174
|
-
# #
|
341
|
+
# # @subscriber.begin if @subscriber
|
342
|
+
# # end
|
175
343
|
# #
|
176
|
-
# #
|
344
|
+
# # # ✅ ADD THIS METHOD
|
345
|
+
# # def connected?
|
346
|
+
# # @client && @client.respond_to?(:connected?) && @client.connected?
|
347
|
+
# # end
|
177
348
|
# #
|
178
|
-
# #
|
179
|
-
# #
|
180
|
-
# #
|
181
|
-
# #
|
349
|
+
# # def health_check
|
350
|
+
# # {
|
351
|
+
# # nats_connected: connected?,
|
352
|
+
# # database_connected: database_connected?,
|
353
|
+
# # nats_url: @config.nats_url,
|
354
|
+
# # nats_server_url: @config.nats_server_url,
|
355
|
+
# # service_name: @config.service_name,
|
356
|
+
# # version: @config.version,
|
357
|
+
# # instance_id: @config.instance_id,
|
358
|
+
# # published_subjects: @config.subject_patterns,
|
359
|
+
# # timestamp: Time.current.iso8601,
|
360
|
+
# # model_registry_stats: NatsWave::ModelRegistry.subscription_stats
|
361
|
+
# # }
|
182
362
|
# # end
|
183
363
|
# #
|
184
364
|
# # def disconnect!
|
@@ -187,7 +367,13 @@
|
|
187
367
|
# # NatsWave.logger.info "🛑 Shutting down NatsWave client..."
|
188
368
|
# #
|
189
369
|
# # @subscriber&.reset
|
190
|
-
# #
|
370
|
+
# #
|
371
|
+
# # if @client&.respond_to?(:close)
|
372
|
+
# # @client.close
|
373
|
+
# # elsif @client&.respond_to?(:disconnect)
|
374
|
+
# # @client.disconnect
|
375
|
+
# # end
|
376
|
+
# #
|
191
377
|
# # @connection_pool&.shutdown
|
192
378
|
# # @connection_pool&.wait_for_termination(5)
|
193
379
|
# #
|
@@ -196,29 +382,6 @@
|
|
196
382
|
# #
|
197
383
|
# # private
|
198
384
|
# #
|
199
|
-
# # def setup_signal_handlers
|
200
|
-
# # # Handle graceful shutdown
|
201
|
-
# # ['INT', 'TERM'].each do |signal|
|
202
|
-
# # Signal.trap(signal) do
|
203
|
-
# # NatsWave.logger.info "🛑 Received #{signal}, shutting down gracefully..."
|
204
|
-
# # disconnect!
|
205
|
-
# # exit(0)
|
206
|
-
# # end
|
207
|
-
# # end
|
208
|
-
# # end
|
209
|
-
# #
|
210
|
-
# # def keep_main_thread_alive
|
211
|
-
# # # This prevents the main thread from exiting in console/rake tasks
|
212
|
-
# # Thread.new do
|
213
|
-
# # while !@shutdown
|
214
|
-
# # sleep 1
|
215
|
-
# # end
|
216
|
-
# # end.join
|
217
|
-
# # rescue Interrupt
|
218
|
-
# # NatsWave.logger.info "🛑 Interrupted, shutting down..."
|
219
|
-
# # disconnect!
|
220
|
-
# # end
|
221
|
-
# #
|
222
385
|
# # def setup_connection_pool
|
223
386
|
# # return unless defined?(Concurrent)
|
224
387
|
# #
|
@@ -270,8 +433,11 @@
|
|
270
433
|
# # raise ConnectionError, "Failed to connect to NATS: #{e.message}"
|
271
434
|
# # end
|
272
435
|
# #
|
436
|
+
# # # ✅ UPDATE THIS METHOD
|
273
437
|
# # def ensure_connected!
|
274
|
-
# #
|
438
|
+
# # unless connected?
|
439
|
+
# # raise ConnectionError, "Not connected to NATS. NATS client: #{@client.class rescue 'nil'}"
|
440
|
+
# # end
|
275
441
|
# # end
|
276
442
|
# #
|
277
443
|
# # def database_connected?
|
@@ -289,6 +455,13 @@
|
|
289
455
|
#
|
290
456
|
# # frozen_string_literal: true
|
291
457
|
#
|
458
|
+
# begin
|
459
|
+
# require 'nats/client'
|
460
|
+
# rescue LoadError => e
|
461
|
+
# # NATS gem not available
|
462
|
+
# puts "Warning: NATS gem not available: #{e.message}"
|
463
|
+
# end
|
464
|
+
#
|
292
465
|
# module NatsWave
|
293
466
|
# class Client
|
294
467
|
# attr_reader :config, :publisher, :subscriber, :client
|
@@ -341,7 +514,6 @@
|
|
341
514
|
# @subscriber.begin if @subscriber
|
342
515
|
# end
|
343
516
|
#
|
344
|
-
# # ✅ ADD THIS METHOD
|
345
517
|
# def connected?
|
346
518
|
# @client && @client.respond_to?(:connected?) && @client.connected?
|
347
519
|
# end
|
@@ -351,11 +523,9 @@
|
|
351
523
|
# nats_connected: connected?,
|
352
524
|
# database_connected: database_connected?,
|
353
525
|
# nats_url: @config.nats_url,
|
354
|
-
# nats_server_url: @config.nats_server_url,
|
355
526
|
# service_name: @config.service_name,
|
356
527
|
# version: @config.version,
|
357
528
|
# instance_id: @config.instance_id,
|
358
|
-
# published_subjects: @config.subject_patterns,
|
359
529
|
# timestamp: Time.current.iso8601,
|
360
530
|
# model_registry_stats: NatsWave::ModelRegistry.subscription_stats
|
361
531
|
# }
|
@@ -408,35 +578,144 @@
|
|
408
578
|
# end
|
409
579
|
#
|
410
580
|
# def establish_connections
|
411
|
-
#
|
581
|
+
# unless nats_available?
|
582
|
+
# NatsWave.logger.warn "NATS gem not available, skipping connection"
|
583
|
+
# return
|
584
|
+
# end
|
585
|
+
#
|
586
|
+
# unless test_nats_connectivity
|
587
|
+
# NatsWave.logger.error "Cannot reach NATS server, skipping connection"
|
588
|
+
# return
|
589
|
+
# end
|
412
590
|
#
|
591
|
+
# # Always try to establish NATS connection
|
413
592
|
# establish_nats_connection
|
414
593
|
#
|
415
|
-
#
|
594
|
+
# # Verify connection was successful before creating publisher/subscriber
|
595
|
+
# unless connected?
|
596
|
+
# NatsWave.logger.error "NATS connection failed, cannot initialize publisher/subscriber"
|
597
|
+
# return
|
598
|
+
# end
|
599
|
+
#
|
600
|
+
# # Only create publisher/subscriber if we have a valid connection
|
601
|
+
# if @config.publishing_enabled && connected?
|
416
602
|
# @publisher = Publisher.new(@config, @client, @middleware_stack)
|
603
|
+
# NatsWave.logger.debug "Publisher initialized"
|
417
604
|
# end
|
418
605
|
#
|
419
|
-
# if @config.subscription_enabled
|
606
|
+
# if @config.subscription_enabled && connected?
|
420
607
|
# @subscriber = Subscriber.new(@config, @client, @middleware_stack)
|
608
|
+
# NatsWave.logger.debug "Subscriber initialized"
|
421
609
|
# end
|
422
610
|
# end
|
423
611
|
#
|
424
612
|
# def establish_nats_connection
|
613
|
+
# NatsWave.logger.info "Attempting to connect to NATS at #{@config.nats_url}"
|
614
|
+
#
|
425
615
|
# @client = NATS.connect(
|
426
616
|
# @config.nats_url,
|
427
617
|
# reconnect_time_wait: @config.retry_delay,
|
428
|
-
# max_reconnect_attempts: @config.reconnect_attempts
|
618
|
+
# max_reconnect_attempts: @config.reconnect_attempts,
|
619
|
+
# ping_interval: 20,
|
620
|
+
# max_outstanding_pings: 2,
|
621
|
+
# disconnected_cb: proc do |reason|
|
622
|
+
# NatsWave.logger.warn "🔌 NATS disconnected: #{reason}"
|
623
|
+
# end,
|
624
|
+
# reconnected_cb: proc do
|
625
|
+
# NatsWave.logger.info "🔌 NATS auto-reconnected"
|
626
|
+
# end,
|
627
|
+
# error_cb: proc do |error|
|
628
|
+
# NatsWave.logger.error "🔌 NATS error: #{error}"
|
629
|
+
# end
|
429
630
|
# )
|
430
|
-
#
|
631
|
+
#
|
632
|
+
# # Verify the connection actually worked
|
633
|
+
# if @client&.connected?
|
634
|
+
# NatsWave.logger.info "✅ Successfully connected to NATS at #{@config.nats_url}"
|
635
|
+
# else
|
636
|
+
# NatsWave.logger.error "❌ NATS client created but not connected"
|
637
|
+
# @client = nil
|
638
|
+
# end
|
639
|
+
#
|
431
640
|
# rescue => e
|
432
|
-
# NatsWave.logger.error
|
433
|
-
#
|
641
|
+
# NatsWave.logger.error "❌ Failed to connect to NATS: #{e.message}"
|
642
|
+
# NatsWave.logger.error "NATS URL: #{@config.nats_url}"
|
643
|
+
# NatsWave.logger.error "Error class: #{e.class}"
|
644
|
+
#
|
645
|
+
# @client = nil
|
646
|
+
#
|
647
|
+
# # Re-raise in development to catch issues early
|
648
|
+
# if defined?(Rails) && Rails.env.development?
|
649
|
+
# raise ConnectionError, "Failed to connect to NATS: #{e.message}"
|
650
|
+
# end
|
434
651
|
# end
|
435
652
|
#
|
436
|
-
# #
|
653
|
+
# # def establish_nats_connection
|
654
|
+
# # NatsWave.logger.info "Attempting to connect to NATS at #{@config.nats_url}"
|
655
|
+
# #
|
656
|
+
# # # Add more detailed connection options for debugging
|
657
|
+
# # connection_options = {
|
658
|
+
# # reconnect_time_wait: @config.retry_delay,
|
659
|
+
# # max_reconnect_attempts: @config.reconnect_attempts,
|
660
|
+
# # dont_randomize_servers: true,
|
661
|
+
# # verbose: true,
|
662
|
+
# # pedantic: false
|
663
|
+
# # }
|
664
|
+
# #
|
665
|
+
# # NatsWave.logger.info "Connection options: #{connection_options}"
|
666
|
+
# #
|
667
|
+
# # @client = NATS.connect(@config.nats_url, connection_options)
|
668
|
+
# #
|
669
|
+
# # # Wait a moment for connection to establish
|
670
|
+
# # sleep 0.5
|
671
|
+
# #
|
672
|
+
# # # Check connection status with more detail
|
673
|
+
# # if @client
|
674
|
+
# # NatsWave.logger.info "NATS client created: #{@client.class}"
|
675
|
+
# # NatsWave.logger.info "NATS client connected?: #{@client.connected?}"
|
676
|
+
# # NatsWave.logger.info "NATS client status: #{@client.status rescue 'unknown'}"
|
677
|
+
# #
|
678
|
+
# # if @client.connected?
|
679
|
+
# # NatsWave.logger.info "✅ Successfully connected to NATS at #{@config.nats_url}"
|
680
|
+
# # else
|
681
|
+
# # NatsWave.logger.error "❌ NATS client created but not connected"
|
682
|
+
# # NatsWave.logger.error "Client last error: #{@client.last_error rescue 'none'}"
|
683
|
+
# # @client = nil
|
684
|
+
# # end
|
685
|
+
# # else
|
686
|
+
# # NatsWave.logger.error "❌ NATS client is nil after connection attempt"
|
687
|
+
# # end
|
688
|
+
# #
|
689
|
+
# # rescue => e
|
690
|
+
# # NatsWave.logger.error "❌ Failed to connect to NATS: #{e.message}"
|
691
|
+
# # NatsWave.logger.error "Error class: #{e.class}"
|
692
|
+
# # NatsWave.logger.error "Error backtrace: #{e.backtrace.first(5).join('\n')}"
|
693
|
+
# # NatsWave.logger.error "NATS URL: #{@config.nats_url}"
|
694
|
+
# # NatsWave.logger.error "Retry delay: #{@config.retry_delay}"
|
695
|
+
# # NatsWave.logger.error "Max reconnect attempts: #{@config.reconnect_attempts}"
|
696
|
+
# #
|
697
|
+
# # @client = nil
|
698
|
+
# #
|
699
|
+
# # # Re-raise in development to catch issues early
|
700
|
+
# # if defined?(Rails) && Rails.env.development?
|
701
|
+
# # raise ConnectionError, "Failed to connect to NATS: #{e.message}"
|
702
|
+
# # end
|
703
|
+
# # end
|
704
|
+
#
|
437
705
|
# def ensure_connected!
|
438
706
|
# unless connected?
|
439
|
-
#
|
707
|
+
# error_msg = if @client.nil?
|
708
|
+
# "NATS client is nil - connection failed during initialization"
|
709
|
+
# else
|
710
|
+
# "NATS client exists but not connected (#{@client.class})"
|
711
|
+
# end
|
712
|
+
#
|
713
|
+
# NatsWave.logger.error "🔴 Connection check failed: #{error_msg}"
|
714
|
+
# NatsWave.logger.error "🔧 NATS URL: #{@config.nats_url}"
|
715
|
+
# NatsWave.logger.error "🔧 Publishing enabled: #{@config.publishing_enabled}"
|
716
|
+
# NatsWave.logger.error "🔧 Subscription enabled: #{@config.subscription_enabled}"
|
717
|
+
#
|
718
|
+
# raise ConnectionError, error_msg
|
440
719
|
# end
|
441
720
|
# end
|
442
721
|
#
|
@@ -446,13 +725,43 @@
|
|
446
725
|
# end
|
447
726
|
#
|
448
727
|
# def nats_available?
|
728
|
+
# # First, try to require the NATS gem if it's not already loaded
|
729
|
+
# begin
|
730
|
+
# require 'nats/client' unless defined?(NATS)
|
731
|
+
# rescue LoadError
|
732
|
+
# NatsWave.logger.error "❌ NATS gem not found. Add 'gem \"nats\"' to your Gemfile"
|
733
|
+
# return false
|
734
|
+
# end
|
735
|
+
#
|
736
|
+
# # Then check if the NATS constant is defined
|
449
737
|
# defined?(NATS)
|
450
|
-
#
|
451
|
-
#
|
738
|
+
# end
|
739
|
+
#
|
740
|
+
# def test_nats_connectivity
|
741
|
+
# require 'socket'
|
742
|
+
# require 'uri'
|
743
|
+
#
|
744
|
+
# begin
|
745
|
+
# uri = URI.parse(@config.nats_url)
|
746
|
+
# host = uri.host || 'localhost'
|
747
|
+
# port = uri.port || 4222
|
748
|
+
#
|
749
|
+
# NatsWave.logger.info "Testing TCP connectivity to #{host}:#{port}"
|
750
|
+
#
|
751
|
+
# socket = TCPSocket.new(host, port)
|
752
|
+
# socket.close
|
753
|
+
#
|
754
|
+
# NatsWave.logger.info "✅ TCP connection to NATS server successful"
|
755
|
+
# true
|
756
|
+
# rescue => e
|
757
|
+
# NatsWave.logger.error "❌ Cannot reach NATS server: #{e.message}"
|
758
|
+
# false
|
759
|
+
# end
|
452
760
|
# end
|
453
761
|
# end
|
454
762
|
# end
|
455
763
|
|
764
|
+
|
456
765
|
# frozen_string_literal: true
|
457
766
|
|
458
767
|
begin
|
@@ -611,7 +920,7 @@ module NatsWave
|
|
611
920
|
|
612
921
|
def establish_nats_connection
|
613
922
|
NatsWave.logger.info "Attempting to connect to NATS at #{@config.nats_url}"
|
614
|
-
|
923
|
+
|
615
924
|
@client = NATS.connect(
|
616
925
|
@config.nats_url,
|
617
926
|
reconnect_time_wait: @config.retry_delay,
|
@@ -628,7 +937,7 @@ module NatsWave
|
|
628
937
|
NatsWave.logger.error "🔌 NATS error: #{error}"
|
629
938
|
end
|
630
939
|
)
|
631
|
-
|
940
|
+
|
632
941
|
# Verify the connection actually worked
|
633
942
|
if @client&.connected?
|
634
943
|
NatsWave.logger.info "✅ Successfully connected to NATS at #{@config.nats_url}"
|
@@ -636,72 +945,20 @@ module NatsWave
|
|
636
945
|
NatsWave.logger.error "❌ NATS client created but not connected"
|
637
946
|
@client = nil
|
638
947
|
end
|
639
|
-
|
948
|
+
|
640
949
|
rescue => e
|
641
950
|
NatsWave.logger.error "❌ Failed to connect to NATS: #{e.message}"
|
642
951
|
NatsWave.logger.error "NATS URL: #{@config.nats_url}"
|
643
952
|
NatsWave.logger.error "Error class: #{e.class}"
|
644
|
-
|
953
|
+
|
645
954
|
@client = nil
|
646
|
-
|
955
|
+
|
647
956
|
# Re-raise in development to catch issues early
|
648
957
|
if defined?(Rails) && Rails.env.development?
|
649
958
|
raise ConnectionError, "Failed to connect to NATS: #{e.message}"
|
650
959
|
end
|
651
960
|
end
|
652
961
|
|
653
|
-
# def establish_nats_connection
|
654
|
-
# NatsWave.logger.info "Attempting to connect to NATS at #{@config.nats_url}"
|
655
|
-
#
|
656
|
-
# # Add more detailed connection options for debugging
|
657
|
-
# connection_options = {
|
658
|
-
# reconnect_time_wait: @config.retry_delay,
|
659
|
-
# max_reconnect_attempts: @config.reconnect_attempts,
|
660
|
-
# dont_randomize_servers: true,
|
661
|
-
# verbose: true,
|
662
|
-
# pedantic: false
|
663
|
-
# }
|
664
|
-
#
|
665
|
-
# NatsWave.logger.info "Connection options: #{connection_options}"
|
666
|
-
#
|
667
|
-
# @client = NATS.connect(@config.nats_url, connection_options)
|
668
|
-
#
|
669
|
-
# # Wait a moment for connection to establish
|
670
|
-
# sleep 0.5
|
671
|
-
#
|
672
|
-
# # Check connection status with more detail
|
673
|
-
# if @client
|
674
|
-
# NatsWave.logger.info "NATS client created: #{@client.class}"
|
675
|
-
# NatsWave.logger.info "NATS client connected?: #{@client.connected?}"
|
676
|
-
# NatsWave.logger.info "NATS client status: #{@client.status rescue 'unknown'}"
|
677
|
-
#
|
678
|
-
# if @client.connected?
|
679
|
-
# NatsWave.logger.info "✅ Successfully connected to NATS at #{@config.nats_url}"
|
680
|
-
# else
|
681
|
-
# NatsWave.logger.error "❌ NATS client created but not connected"
|
682
|
-
# NatsWave.logger.error "Client last error: #{@client.last_error rescue 'none'}"
|
683
|
-
# @client = nil
|
684
|
-
# end
|
685
|
-
# else
|
686
|
-
# NatsWave.logger.error "❌ NATS client is nil after connection attempt"
|
687
|
-
# end
|
688
|
-
#
|
689
|
-
# rescue => e
|
690
|
-
# NatsWave.logger.error "❌ Failed to connect to NATS: #{e.message}"
|
691
|
-
# NatsWave.logger.error "Error class: #{e.class}"
|
692
|
-
# NatsWave.logger.error "Error backtrace: #{e.backtrace.first(5).join('\n')}"
|
693
|
-
# NatsWave.logger.error "NATS URL: #{@config.nats_url}"
|
694
|
-
# NatsWave.logger.error "Retry delay: #{@config.retry_delay}"
|
695
|
-
# NatsWave.logger.error "Max reconnect attempts: #{@config.reconnect_attempts}"
|
696
|
-
#
|
697
|
-
# @client = nil
|
698
|
-
#
|
699
|
-
# # Re-raise in development to catch issues early
|
700
|
-
# if defined?(Rails) && Rails.env.development?
|
701
|
-
# raise ConnectionError, "Failed to connect to NATS: #{e.message}"
|
702
|
-
# end
|
703
|
-
# end
|
704
|
-
|
705
962
|
def ensure_connected!
|
706
963
|
unless connected?
|
707
964
|
error_msg = if @client.nil?
|