fix: restore away status after websocket reconnection

Merged
RO
2mo ago
+300-26

Proposed changes (including videos or screenshots)

Auto-away is lost on every websocket reconnection.

Presence.newConnection() registers every new DDP session as online, and the client kept no memory of activity across the drop — it assumed the reconnected session was online and restarted the idle countdown from zero. An idle user came back online on every reconnect and stayed online for a full idle period; on desktop indefinitely, since the OS idle poller only reports state changes. Any infrastructure that recycles long-lived connections on a timer (HAProxy timeout tunnel, nginx proxy_read_timeout, ALB/Cloudflare idle timeouts, LB failover, restarts) reproduces this workspace-wide on that cadence.

The client now:

  • tracks lastActivityAt across drops, so disconnected time counts as inactivity;
  • restates away once the reconnected session is authenticated, instead of assuming online;
  • schedules the idle timer for the remaining time, not a fresh full period;
  • records the idle state at the away entry point, so an idle transition reported by the desktop app while disconnected is no longer dropped;
  • only forces away when enableAutoAway is enabled.

It also fixes the countdown being restarted by unrelated user-document updates: the effect now depends on user?._id instead of the whole user object, which minted a new reference on every store update.

Steps to test or reproduce

Use two accounts — checking A's own UI means moving the pointer into A's window, which resets the idle countdown, so observe from B instead.

  1. In Admin → Settings → Accounts → Default User Preferences, enable Enable Auto Away, set Idle Time Limit to 60s, reload.

  2. Open A (your user) in a normal window and B (another user) in incognito, with B viewing A in a DM so A's status dot is visible.

  3. In A, undock DevTools into a separate window and stop touching A's window. Once the idle limit passes, B shows A as away.

  4. In A's console, trigger a reconnect and leave it alone:

    Meteor.disconnect(); setTimeout(() => Meteor.reconnect(), 5000);
    
  5. Watch B: A goes offline, then online on reconnect, then back to away within a round trip, with no interaction. Before this PR, A stayed online for a full idle period.

Undocking matters: the client listens for mousemove/mousedown/keydown on the document and focus on the window, so with the console docked, merely moving the pointer across the page to reach it stamps lastActivityAt and legitimately brings A online. Once undocked, stay in the DevTools window.

Issues

Further comments

  • The server still writes online in newConnection and broadcasts it, so there is a ~1 round-trip window where clients see the user online before the away lands.
  • The non-idle branch intentionally does not send UserPresence:online: the session is already online server-side, so it would add a method call plus a presence broadcast per client on every reconnect, doubling presence work on a mass reconnect for no gain.
  • Mobile needs no equivalent change — it already re-asserts away on the resume login via checkBackgroundAndSetAway.
  • Why not server-side. Preserving the previous status in newConnection sounds cheaper, but nothing is left to preserve: connection.onClose → removeConnection already recomputed the user to offline before the reconnect arrives. It would need new persisted state, a rule keeping bots and API clients defaulting to online, and the client declaring online so nobody gets stuck away — a lot of machinery to close a sub-second window, for something the server cannot observe anyway. Only the client knows whether the user is idle.

https://claude.ai/code/session_01PQu7gFiCHs1nyDtq3Wmufi

Summary by CodeRabbit

Summary by CodeRabbit

  • Bug Fixes
    • Preserved users’ away status and inactivity progress after websocket reconnections.
    • Restored online status when users interact while disconnected.
    • Improved presence updates during login, reconnection, and connection changes.
    • Ensured desktop and browser activity consistently resets away status.
    • Prevented inactivity timers from restarting unnecessarily after reconnecting.
    • More accurately restored presence based on the user’s latest activity.