Skip to content

Detect a dead WebSocket and say why ingress stopped - #27

Open
duharry0915 wants to merge 1 commit into
mainfrom
fix/websocket-liveness
Open

duharry0915 wants to merge 1 commit into
mainfrom
fix/websocket-liveness

Conversation

@duharry0915

Copy link
Copy Markdown
Contributor

Refs #23.

What #23 showed

The plugin logged AgentMail WebSocket subscribed, then nothing: no close, no reconnect, no socket. That pattern can't be diagnosed or recovered from the plugin today, for three reasons:

  • The "subscribed" line was written when the frame was sent, not when the server confirmed it. The server acks every subscribe with a subscribed frame and reports failures with an error frame. The plugin dropped both.
  • A socket that disappears without a close event is never recreated. Reconnect was driven only by close and error.
  • An abort ended the whole ingress without a line. That includes the socket and the REST catch-up workers.

Change

All of it is in src/channel/src/websocket.ts:

  • Truthful subscribe log: subscribed is logged when the server acks. If no ack arrives within 30s, or the server answers with an error frame, the connection is recycled through the existing backoff.
  • Idle watchdog: a connection that sees no frame for 20 minutes is recycled. The server closes an idle socket after 10 minutes, so 20 minutes of silence with no close means the socket is gone. Any frame re-arms the deadline. A quiet but healthy socket is still left alone until the server closes it, as before.
  • Diagnosable logs:
    • Server error frames are logged as name: message.
    • The close line now says why the connection ended: the close code and reason, no frames for 20 minutes, subscription not confirmed within 30s, or subscription refused.
    • The ingress logs AgentMail WebSocket ingress stopped for account … when it ends.

REST catch-up already ran on its own timers independent of the socket. It still stops only when the account is aborted, and now that stop is logged.

What this does not settle

I could not reproduce #23. If the socket was dying without a close, the watchdog now recovers it within 20 minutes. If the host was aborting the account, this change won't stop that, but the ingress stopped line will now show it in the reporter's logs. With 0.2.4 the reporter's logs should tell the two apart.

Tests

  • 5 new cases in websocket.test.ts: the ack-gated log, the ack timeout, the idle recycle (including re-arming on a frame), a refused subscription, and close-code logging after a non-fatal server error. All 5 fail on main and pass here.
  • The quiet-socket test now acks the subscription, which is the real healthy path.
  • npm test: 251/251 pass. npm run build is clean.

🤖 Generated with Claude Code

The plugin logged "subscribed" when it sent the subscribe frame and
dropped every non-message frame, so the server's ack and its error
frames were never seen. A socket that disappeared without a close event
was never recreated, and an abort ended the whole ingress silently.

Log "subscribed" only on the server's ack, and reconnect when no ack
arrives within 30s or the server refuses the subscription. Recycle a
connection that sees no frame for 20 minutes, twice the server's idle
close. Log server error frames, the close code and reason, and the
ingress stop.

Refs #23

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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