datagrout-conduit 0.8.1 → 0.8.2

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: fd14b15aedac0053578b8851d4f0bb7295be8fde2f8495010eb8f0591193f91a
4
- data.tar.gz: 33ba69cb106483c8bdfe1bd28f9e0f08135a6bcdbb1ef385c94d2ea014a2f304
3
+ metadata.gz: b5f3083e66b890a25b3fe77e4fd86e7e72ba3d86af8a530477ad93334de26f19
4
+ data.tar.gz: 16bb086f9c923bacad3fe8fc228eb5ea024a475a33bba51f320aad00fa032f56
5
5
  SHA512:
6
- metadata.gz: f168042023a468b2039c42236e29d0b0671d64c8fa807a4c58fd5eab5a2db1ef9c51049dc5f53fe8555eea86818eb513436b27eeac1d8e366d5823c1076a1b89
7
- data.tar.gz: d5ee5d3d4fb4931072596811daabb01d527f08eac8f3a080a83ed700cb8069716c71489cc8cc92f2831ee740b09af5bb1f16f9c98f1a6eaaaa4fd6e63241a889
6
+ metadata.gz: a38b2be0474f517414da7731565fac6a4327664f84b7b95f9e04d478f29183087ac4da84899fbba952bbba11244386735ecd564c1a422038c8baef3b45141d10
7
+ data.tar.gz: 82f0c8a811e8165f1a5c91dcc5c3f93121115cc49d9969774e6b0a2c65d63afb2cf34d646c1042039f52182db2bca2084982d75dee76c56c0ad612405132ec66
data/README.md CHANGED
@@ -310,7 +310,7 @@ Supported topics:
310
310
  | `flows.<flow_id>.*` | `flow.into` progress and completion |
311
311
  | `governor.<server_uuid>` | Governor percept events (file change, schedule, webhook) |
312
312
 
313
- **Reconnection**: after a disconnect, `send_request` and `subscribe` raise `DatagroutConduit::NotInitializedError`. Call `client.connect` again and re-subscribe — subscriptions do not survive reconnects in v0.4.
313
+ **Reconnection**: after a disconnect, `send_request` and `subscribe` raise `DatagroutConduit::NotInitializedError`. Call `client.connect` again and re-subscribe — subscriptions do not survive reconnects in v0.4. A connection ends when the server closes it, a read fails, or a keepalive ping goes unanswered for a whole interval; in-flight calls then fail and every subscription's `each` ends.
314
314
 
315
315
  ## Standard MCP Methods
316
316
 
@@ -442,6 +442,19 @@ module DatagroutConduit
442
442
  subs.each_value { |list| list.each(&:_close) }
443
443
  end
444
444
 
445
+ # The peer stopped answering pings: release every waiter as a close
446
+ # does, then close the socket so the read thread stops too.
447
+ def peer_gone
448
+ was_connected = @mutex.synchronize do
449
+ old = @connected
450
+ @connected = false
451
+ old
452
+ end
453
+
454
+ fail_all_pending(:ping_timeout) if was_connected
455
+ @io&.close rescue nil
456
+ end
457
+
445
458
  def cleanup_socket
446
459
  stop_ping_thread
447
460
  @write_mutex.synchronize do
@@ -458,11 +471,17 @@ module DatagroutConduit
458
471
  # Start the background ping thread. Sends one WS ping frame every
459
472
  # @ping_interval seconds until the connection is torn down. No-op when
460
473
  # @ping_interval is non-positive (used by tests to disable pinging).
474
+ #
475
+ # A ping still unanswered when the next is due closes the connection: a
476
+ # peer that vanished without a close frame (a dropped NAT mapping, a
477
+ # host that went away) is otherwise invisible until the OS gives up on
478
+ # the TCP connection.
461
479
  def start_ping_thread
462
480
  return if @ping_thread
463
481
  return if @ping_interval <= 0
464
482
 
465
483
  interval = @ping_interval
484
+ @awaiting_pong = false
466
485
  @ping_thread = Thread.new do
467
486
  loop do
468
487
  sleep interval
@@ -471,15 +490,26 @@ module DatagroutConduit
471
490
  driver = @driver
472
491
  break unless driver
473
492
 
493
+ if @awaiting_pong
494
+ peer_gone
495
+ break
496
+ end
497
+
474
498
  begin
475
499
  # WebSocket::Driver#ping returns false if the connection is
476
- # already closing; treat that as "stop the loop" too.
477
- @write_mutex.synchronize { driver.ping } || break
500
+ # already closing; treat that as "stop the loop" too. Its block
501
+ # runs when the matching pong arrives.
502
+ @awaiting_pong = true
503
+ @write_mutex.synchronize { driver.ping { @awaiting_pong = false } } || break
478
504
  @pings_sent += 1
479
505
  rescue StandardError
480
506
  break
481
507
  end
482
508
  end
509
+ ensure
510
+ # A loop that ended on its own must not stop the next connect from
511
+ # starting a fresh one.
512
+ @ping_thread = nil if @ping_thread == Thread.current
483
513
  end
484
514
  @ping_thread.abort_on_exception = false
485
515
  @ping_thread.name = "conduit-ws-ping"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DatagroutConduit
4
- VERSION = "0.8.1"
4
+ VERSION = "0.8.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datagrout-conduit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - DataGrout