Repository navigation
🐛 Destroy every stream an Agent holds when it closes - #751
alecgibson wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
In-flight presence broadcasts can survive cleanup, and synthetic disconnect messages include an invalid sequence value.
2 open findings
What changed in this PR
Tracks Agent-owned streams for reliable cleanup and broadcasts null presence on unsubscribe or disconnect.
Changes:
- Adds centralized stream tracking and cleanup.
- Moves presence-disconnect broadcasts into explicit cleanup paths.
- Adds tests and documents null presence behavior.
| File | Description |
|---|---|
lib/agent.js |
Implements stream tracking and presence cleanup. |
test/agent.js |
Tests cleanup of all stream types. |
test/client/presence/presence.js |
Tests null presence broadcasts. |
docs/api/presence.md |
Documents unsubscribe behavior. |
docs/middleware/actions.md |
Documents null middleware presence. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
84cb60e to
c5c9a12
Compare
Fixes #740 Fixes #748 At the moment, `Agent._cleanup()` only destroys streams that are still in each subscription path's own map, so any bookkeeping slip in one of those paths leaves a stream subscribed after the client disconnects. This change tracks every stream handed to the agent in one map, and destroys them all on cleanup. So that presence streams can be replaced like doc streams, the `p: null` "client left" broadcast moves off the presence stream's `'end'` and into `_unsubscribePresence()` and `_cleanup()`. A broadcast still in middleware at that point goes out as `p: null` instead. That also fixes presence outliving its client when it was never subscribed, or still in flight, which `receivePresence` middleware now sees as `p: null`: 1. Client A submits presence on a channel it hasn't subscribed to 2. Client B, subscribed to the channel, receives it 3. Client A disconnects, and B keeps A's presence forever 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
c5c9a12 to
7c1a081
Compare
Migration noteNot breaking. This can ship as a 6.x 🐛 fix. On
On backend.use('receivePresence', function(context, next) {
if (context.presence.p === null) return next();
// ...
}); |



Fixes #740
Fixes #748
At the moment,
Agent._cleanup()only destroys streams that are still in each subscription path's own map, so any bookkeeping slip in one of those paths leaves a stream subscribed after the client disconnects.This change tracks every stream handed to the agent in one map, and destroys them all on cleanup. So that presence streams can be replaced like doc streams, the
p: null"client left" broadcast moves off the presence stream's'end'and into_unsubscribePresence()and_cleanup(). A broadcast still in middleware at that point goes out asp: nullinstead.That also fixes presence outliving its client when it was never subscribed, or still in flight, which
receivePresencemiddleware now sees asp: null:🤖 Generated with Claude Code
Co-Authored-By: Claude noreply@anthropic.com