Skip to content

Discord health-monitor: stale-socket triggers full gateway restart instead of surgical reconnect #56086

Description

@sahan-silva

Description

The health-monitor's stale-socket detection for the Discord provider triggers a full gateway restart instead of reconnecting only the Discord WebSocket. This causes significant downtime for users with active Discord integrations.

Impact

  • 22+ full gateway restarts per day on our setup
  • 10-15 seconds of total downtime per restart (crons interrupted, Discord offline, canvas unmounted)
  • Cumulative: ~5 minutes of avoidable downtime per day
  • 445 stale-socket restarts observed in one log rotation window

Evidence

# Consistent 35-65 minute cycle
2026-03-27T22:19:58 [health-monitor] started (interval: 300s)
2026-03-27T23:24:58 [health-monitor] [discord:default] restarting (reason: stale-socket)
2026-03-28T00:25:04 [health-monitor] [discord:default] restarting (reason: stale-socket)
2026-03-28T00:31:24 [discord] gateway: WebSocket connection closed with code 1006
2026-03-28T01:26:06 [discord] gateway: WebSocket connection closed with code 1005
2026-03-28T02:00:12 [health-monitor] [discord:default] restarting (reason: stale-socket)

Close codes: 1006 (abnormal — no close frame), 1005 (library timeout)

Root Cause Hypothesis

Discord heartbeat starvation during heavy cron execution. With 40+ cron jobs (some spawning Claude CLI subprocesses), the Node.js event loop is contended. When blocked for >41.25s (Discord's heartbeat interval), Discord drops the WebSocket. The health-monitor detects the stale socket and restarts the entire gateway.

Suggested Improvements

  1. Surgical Discord reconnect (P1): When stale-socket is Discord-specific, call discord.provider.reconnect() instead of gateway.restart(). This preserves the gateway, cron scheduler, canvas host, and all other services.

  2. Configurable stale threshold (P2): Allow setting how many consecutive stale checks before triggering a restart. Currently restarts on first detection. Threshold of 2-3 would allow transient drops to self-heal via Discord's built-in resume.

  3. Discord heartbeat jitter config (P3): Expose discord.heartbeatJitterMs to send heartbeats slightly early, providing headroom during event loop contention.

Environment

  • OpenClaw: 2026.3.24
  • macOS Darwin 25.3.0, Mac Mini M4 Pro
  • Node.js 24 LTS
  • 40+ cron jobs, 17 agents
  • 1 Discord server, 2 channels, Message Content Intent enabled

Workaround

Deployed a launchd watchdog that monitors gateway health every 15 minutes and auto-restarts crashed services. Mitigates downtime but doesn't fix root cause.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions