Skip to content

Resilient connections: auto-reconnect and heartbeat#80

Merged
bbatsov merged 3 commits into
masterfrom
resilient-connections
Jun 27, 2026
Merged

Resilient connections: auto-reconnect and heartbeat#80
bbatsov merged 3 commits into
masterfrom
resilient-connections

Conversation

@bbatsov

@bbatsov bbatsov commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Second functionality improvement, built on the native-WebSocket client. The REPL connection now heals itself.

  • Auto-reconnect (on by default): an unexpected drop - page reload, server restart, flaky network - triggers a reconnect with exponential backoff (1s up to a 30s ceiling, reset on success). New weasel.repl/disconnect closes for good and stops retrying.
  • Heartbeat (opt-in via :heartbeat-interval): an app-level :ping/:pong detects a silently dead link and forces a reconnect. It negotiates - a server that never pongs is never disturbed - and the server gained a :ping handler.

Connection state lives in one generation-guarded atom, so superseded sockets can't corrupt a fresh session, timers don't leak across connect calls, and alive? stays honest through failed connects and disconnect.

Worth a careful look: I ran an automated review on the first cut and it found a pile of lifecycle bugs (heartbeat killing healthy sockets, an :occupied reconnect loop, leaked timers, alive? lying). Those are all fixed here, but the reconnect/teardown logic is the part to scrutinize. The Node integration test bounces the server mid-session and asserts eval, print, heartbeat and reconnect all work end to end; a unit test covers the server's pong.

bbatsov added 3 commits June 27, 2026 12:07
Add a :ping handler that replies with :pong, so the client can use an
application-level heartbeat to detect a silently dead connection, plus a
:default no-op so an unknown op never blows up the server's message loop.
The client now reconnects on its own after an unexpected drop (page reload,
server restart, flaky link) using an exponential backoff that only resets once
a socket proves stable, and exposes a new disconnect fn to stop for good. An
optional, opt-in heartbeat detects a silently dead link and forces a reconnect;
it tolerates a few missed pongs before giving up and never disturbs a server
that doesn't answer pings.

Connection state lives in a single generation-guarded atom so superseded
sockets can't corrupt a fresh session, timers never leak across connects, and
alive? stays honest. The Node integration test bounces the server mid-session
and asserts the client reconnects and round-trips again, and checks the
heartbeat keeps pinging without tearing down a healthy socket.
@bbatsov bbatsov force-pushed the resilient-connections branch from a438c56 to b047efa Compare June 27, 2026 09:07
@bbatsov bbatsov merged commit 29a5e47 into master Jun 27, 2026
1 check passed
@bbatsov bbatsov deleted the resilient-connections branch June 27, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant