RocketChat / RocketChat/Rocket.Chat.js.SDK
An Abandoned sub keeps its entry but reports failure, so a retrying caller gets two entries for one stream
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 146
- Forks
- 99
- Avg merge
- 7h 59m
- Merged PRs (30d)
- 17
Description
What
subscribe writes the subscription entry for an Abandoned sub and then tells the caller the request failed:
.catch((err) => {
this.logger.error(`[ddp] Subscribe error: ${err.message}`)
if (err instanceof AbandonedRequest) {
this.rememberSubscription(err.id, name, params, callback)
}
return undefined
})
The entry survives, which is what ADR-0006 intends. But the caller receives undefined, which is indistinguishable from the failure modes that leave nothing behind. A caller that responds the obvious way — by subscribing again — gets a second entry for the same stream under a new id, because subscribe mints a fresh id when none is passed.
Both entries then live in subscriptions, and subscribeAll establishes both at the next Login. The result is two live DDP subscriptions on one stream where the app asked for one: duplicate events delivered to the callback, and an unsubscribe that only ends one of them.
Steps to reproduce
- Subscribe to a stream and let the
subframe be written. - End the connection before the DDP response arrives, so the wait is abandoned and the entry is kept.
- Observe
subscriberesolvesundefined. - Subscribe to the same stream and params again, as a caller seeing a failure would.
- Both entries are present in
subscriptionsunder different ids. - Reconnect.
subscribeAllestablishes both.
Worth deciding
Whether the caller should be able to tell "kept, will be re-established" apart from "nothing left behind" — or whether subscribe should recognise an existing entry for the same name and params instead of adding a second. ADR-0006 states that what a caller receives is unchanged and the bookkeeping is its only concern, so the second option may fit the decision better than changing the return.
Why now
This is reachable on its own, but a send on a Socket that is Transport open while its Liveness chain has lapsed now writes the frame instead of failing before the write, which makes an abandoned-after-write sub considerably more common.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing subscribe's AbandonedRequest catch, the subscriptions bookkeeping, and subscribeAll's reconnect path; compare their behavior with ADR-0006. Reproduce an abandoned sub followed by a retry, then verify the chosen behavior leaves one retained entry and one live DDP subscription after reconnect, with unsubscribe affecting the expected entry.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100