Discussion: Async teardown and what to do about it.
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 31.7k
- Forks
- 3k
- PR merge metrics
- No merged PRs in 30d
Description
WARNING: This is a brain dump and is in NO WAY reflective of any future plans for RxJS.
I just want to put this hear because sometimes people ask about it.
Currently RxJS has no mechanism for handling/waiting for teardown that is asynchronous. This doesn't come up very often, but I've hit it a few times at my day job, and I think it's worth discussing here.
Examples:
- Unsubscribing from a remotely pushed stream may require waiting for confirmation before re-subscribing.
- Tearing down a resource that may not be fully torn down until a later event. (Ignoring a promise resolution, noop-ing in an animation frame, etc)
- Dealing with APIs such as
PushSubscription
Some thoughts:
I'm mostly just getting my thoughts on this down, but I have I few ideas around how this could work in a non-breaking way for RxJS, however, even if it's non-breaking, it might be "new enough" we wouldn't want to surprise people with it in a minor release, I don't know.
- We could start supporting returning either
voidorPromise<any>from teardowns returned from thenew Observableinit, or passed toSubscription.prototype.add. - We could then also provide a method on
Subscriptioncalled likefinally(cb)that returns a promise (because it's guaranteed to emit a value). - We would need to make sure the
finalizeoperators did not fire until after all async teardown had settled.
Concept using Subscription:
// assuming:
interface Resource {
ondata: (e: DataEvent) => void;
onclose: () => void;
unsubscribe(): Promise<void>;
}
const source = new Observable(subscriber => {
const resource = new Resource();
resource.ondata = e => subscriber.next(e.data);
resource.onclose = () => subscriber.complete();
subscriber.add(() => resource.unsubscribe()); // Note the promise return here
});
const subscription = source.subscribe(console.log);
subscription.finally(() => { console.log('torn down') });
Other Considerations:
- We've talked about moving toward
AbortController/AbortSignalas a more universal cancellation mechanism, which also does not really support this. If we decide to handle this use case, it might preclude using that primitive. - We might want to delay the signal of
completeorerroruntil everything is torn down as well. At least in the case of the promise returned byforEach. - If we add a
finally(cb)toSubscription. ThenSubscriptionitself is really athenmethod away from being what is basically a cancellable promise. Hahaha 😄 . At that point,forEachmay not have much value? Or maybe it's the other way around? Promisemay be the wrong type here, because the inevitability is someone will want to cancel their teardown. Then what? It's a tricky problem.
Concept using forEach and AbortSignal:
This is probably more pie in the sky: But in a world where we're using AbortSignal for cancellation, we could keep the same bit as above for the new Observable where we allow async functions in subscriber.add... however, we could have the promise returned by forEach await finalization before resolving/rejecting/finalizing. Just a thought.
Final thoughts
As I look at this problem, I do realize that there are a lot of corner cases that would be solved neatly if all notifications/signals in RxJS were scheduled on a micro task. Which is something I actually hate to admit. However, with regards to teardown, ideally that happens synchronously if possible.
Contributor guide
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
This is a design discussion about asynchronous teardown involving Observable, Subscription, finalize, forEach, and AbortSignal; no implementation files or tests are named. Start by reviewing those APIs and the existing teardown behavior, but the issue does not define a decided approach or concrete completion criteria.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, typescript
- Domain
- api
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100