jetstream_bridge 4.0.3 → 4.0.4

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: fdb73e243bddbd9812d6d454d1975d15f6f8d98325c7759853d32a01c830e27e
4
- data.tar.gz: 8c570f62d4e4b0efddf59e6a4033026b5cabaad83fe808ec0942ad57f3874d5e
3
+ metadata.gz: 3d2af28b3492eb97a04b9337390f71f90786321baf7c50f3f49de3a2cbe1b5c3
4
+ data.tar.gz: 3746cb676e9739a087c295488d85b51a6acec82c4ffca81027726cf33a9ada53
5
5
  SHA512:
6
- metadata.gz: c9b95208ecf116e52daa75e77d3edb62899e6724bec67c72c4322aab31778392906053f77e9eb420c855605ee6aca41eacad9c509b47e5123e710436d201718c
7
- data.tar.gz: 588603c1946d72946c9ba990869869e5932c3f04e265cefbbc2d6f0c3829467e1e498eab307b84770b7d88ed134184d6c8f07596968d0b30da107204fa3bca5f
6
+ metadata.gz: 91cff40e1f076eaee83bf937d10cbbcaaaf0e311fabb347e3ae757d7e7bd0645bcea338cd222cbfcb9d42c37deefd88076d618af2185572ca4cdeb4fa85dea27
7
+ data.tar.gz: 5fc680881fb91c550b8f6561babfd2227a3a9e263d3c07f1bd89a0de61fd835a8bf74b0731603384a16f078b401f22afbdbf31e94d62bac88ed1473f8c0aa15b
data/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.0.4] - 2025-11-23
9
+
10
+ ### Fixed
11
+
12
+ - **NATS Compatibility** - Fix connection failure with nats-pure 2.5.0
13
+ - Handle both object-style and hash-style access for stream_info responses
14
+ - Fixes "undefined method 'streams' for Hash" error during connection establishment
15
+ - Adds compatibility checks using `respond_to?` for config and state attributes
16
+ - Updated 4 files: jetstream_bridge.rb, topology/stream.rb, topology/overlap_guard.rb, debug_helper.rb
17
+ - Maintains backward compatibility with older nats-pure versions
18
+
8
19
  ## [4.0.3] - 2025-11-23
9
20
 
10
21
  ### Added
@@ -81,18 +81,7 @@ module JetstreamBridge
81
81
  cfg = JetstreamBridge.config
82
82
  info = jts.stream_info(cfg.stream_name)
83
83
 
84
- {
85
- name: cfg.stream_name,
86
- exists: true,
87
- subjects: info.config.subjects,
88
- retention: info.config.retention,
89
- storage: info.config.storage,
90
- max_consumers: info.config.max_consumers,
91
- messages: info.state.messages,
92
- bytes: info.state.bytes,
93
- first_seq: info.state.first_seq,
94
- last_seq: info.state.last_seq
95
- }
84
+ build_stream_info(cfg, info)
96
85
  rescue StandardError => e
97
86
  {
98
87
  name: JetstreamBridge.config.stream_name,
@@ -101,6 +90,29 @@ module JetstreamBridge
101
90
  }
102
91
  end
103
92
 
93
+ def build_stream_info(cfg, info)
94
+ # Handle both object-style and hash-style access for compatibility
95
+ config_data = info.config
96
+ state_data = info.state
97
+
98
+ {
99
+ name: cfg.stream_name,
100
+ exists: true,
101
+ subjects: safe_attr(config_data, :subjects),
102
+ retention: safe_attr(config_data, :retention),
103
+ storage: safe_attr(config_data, :storage),
104
+ max_consumers: safe_attr(config_data, :max_consumers),
105
+ messages: safe_attr(state_data, :messages),
106
+ bytes: safe_attr(state_data, :bytes),
107
+ first_seq: safe_attr(state_data, :first_seq),
108
+ last_seq: safe_attr(state_data, :last_seq)
109
+ }
110
+ end
111
+
112
+ def safe_attr(obj, attr)
113
+ obj.respond_to?(attr) ? obj.public_send(attr) : obj[attr]
114
+ end
115
+
104
116
  def log_hash(hash, indent: 0)
105
117
  prefix = ' ' * indent
106
118
  hash.each do |key, value|
@@ -48,7 +48,10 @@ module JetstreamBridge
48
48
  def list_streams_with_subjects(jts)
49
49
  list_stream_names(jts).map do |name|
50
50
  info = jts.stream_info(name)
51
- { name: name, subjects: Array(info.config.subjects || []) }
51
+ # Handle both object-style and hash-style access for compatibility
52
+ config_data = info.config
53
+ subjects = config_data.respond_to?(:subjects) ? config_data.subjects : config_data[:subjects]
54
+ { name: name, subjects: Array(subjects || []) }
52
55
  end
53
56
  end
54
57
 
@@ -127,11 +127,15 @@ module JetstreamBridge
127
127
  private
128
128
 
129
129
  def ensure_update(jts, name, info, desired_subjects)
130
- existing = StreamSupport.normalize_subjects(info.config.subjects || [])
130
+ # Handle both object-style and hash-style access for compatibility
131
+ config_data = info.config
132
+ subjects = config_data.respond_to?(:subjects) ? config_data.subjects : config_data[:subjects]
133
+ existing = StreamSupport.normalize_subjects(subjects || [])
131
134
  to_add = StreamSupport.missing_subjects(existing, desired_subjects)
132
135
 
133
136
  # Retention is immutable; if different, skip all updates to avoid 10052 error.
134
- have_ret = info.config.retention.to_s.downcase
137
+ retention = config_data.respond_to?(:retention) ? config_data.retention : config_data[:retention]
138
+ have_ret = retention.to_s.downcase
135
139
  if have_ret != RETENTION
136
140
  StreamSupport.log_retention_mismatch(name, have: have_ret, want: RETENTION)
137
141
  return
@@ -140,7 +144,8 @@ module JetstreamBridge
140
144
  add_subjects(jts, name, existing, to_add) if to_add.any?
141
145
 
142
146
  # Storage can be updated; do it without passing retention.
143
- have_storage = info.config.storage.to_s.downcase
147
+ storage = config_data.respond_to?(:storage) ? config_data.storage : config_data[:storage]
148
+ have_storage = storage.to_s.downcase
144
149
  if have_storage != STORAGE
145
150
  apply_update(jts, name, existing, storage: STORAGE)
146
151
  StreamSupport.log_config_updated(name, storage: STORAGE)
@@ -4,5 +4,5 @@
4
4
  #
5
5
  # Version constant for the gem.
6
6
  module JetstreamBridge
7
- VERSION = '4.0.3'
7
+ VERSION = '4.0.4'
8
8
  end
@@ -115,21 +115,39 @@ module JetstreamBridge
115
115
  Connection.jetstream
116
116
  end
117
117
 
118
- # Health check for monitoring and readiness probes
118
+ # Active health check for monitoring and readiness probes
119
+ #
120
+ # Performs actual operations to verify system health:
121
+ # - Checks NATS connection (active: calls account_info API)
122
+ # - Verifies stream exists and is accessible (active: queries stream info)
123
+ # - Tests NATS round-trip communication (active: RTT measurement)
119
124
  #
120
125
  # @return [Hash] Health status including NATS connection, stream, and version
121
126
  def health_check
127
+ start_time = Time.now
122
128
  conn_instance = Connection.instance
129
+
130
+ # Active check: calls @jts.account_info internally
123
131
  connected = conn_instance.connected?
124
132
  connected_at = conn_instance.connected_at
125
133
 
134
+ # Active check: queries actual stream from NATS server
126
135
  stream_info = fetch_stream_info if connected
127
136
 
137
+ # Active check: measure NATS round-trip time
138
+ rtt_ms = measure_nats_rtt if connected
139
+
140
+ health_check_duration_ms = ((Time.now - start_time) * 1000).round(2)
141
+
128
142
  {
129
143
  healthy: connected && stream_info&.fetch(:exists, false),
130
144
  nats_connected: connected,
131
145
  connected_at: connected_at&.iso8601,
132
146
  stream: stream_info,
147
+ performance: {
148
+ nats_rtt_ms: rtt_ms,
149
+ health_check_duration_ms: health_check_duration_ms
150
+ },
133
151
  config: {
134
152
  env: config.env,
135
153
  app_name: config.app_name,
@@ -281,11 +299,18 @@ module JetstreamBridge
281
299
  def fetch_stream_info
282
300
  jts = Connection.jetstream
283
301
  info = jts.stream_info(config.stream_name)
302
+
303
+ # Handle both object-style and hash-style access for compatibility
304
+ config_data = info.config
305
+ state_data = info.state
306
+ subjects = config_data.respond_to?(:subjects) ? config_data.subjects : config_data[:subjects]
307
+ messages = state_data.respond_to?(:messages) ? state_data.messages : state_data[:messages]
308
+
284
309
  {
285
310
  exists: true,
286
311
  name: config.stream_name,
287
- subjects: info.config.subjects,
288
- messages: info.state.messages
312
+ subjects: subjects,
313
+ messages: messages
289
314
  }
290
315
  rescue StandardError => e
291
316
  {
@@ -295,6 +320,20 @@ module JetstreamBridge
295
320
  }
296
321
  end
297
322
 
323
+ def measure_nats_rtt
324
+ # Measure round-trip time using NATS RTT method
325
+ nc = Connection.nc
326
+ start = Time.now
327
+ nc.rtt
328
+ ((Time.now - start) * 1000).round(2)
329
+ rescue StandardError => e
330
+ Logging.warn(
331
+ "Failed to measure NATS RTT: #{e.class} #{e.message}",
332
+ tag: 'JetstreamBridge'
333
+ )
334
+ nil
335
+ end
336
+
298
337
  def assign!(cfg, key, val)
299
338
  setter = :"#{key}="
300
339
  raise ArgumentError, "Unknown configuration option: #{key}" unless cfg.respond_to?(setter)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jetstream_bridge
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.3
4
+ version: 4.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Attara