fix: finalize after unsubscription from source #5433
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description:
This PR changes the implementation of
finalize
so that the callback passed to the operator is not called until after the subscriber unsubscribes from its source. The effect of this is that - with this change - finalization happens in same order as completion and unsubscription.Specifically, with unsubscription, we can be sure that when a subscription's
unsubscribe
method returns, every source observable in the chain will have been guaranteed to have been unsubscribed.Without this change,
finalize
's behaviour is very different to that of unsubsciption.The problem is that when
finalize
calls its callback, the observable to which it is applied is still subscribed to any sources and anyfinalize
operators applied to sources further up the composed chain will not have called their finalization callbacks.Aside from this behaviour being surprising, it makes
finalize
pretty much useless for resource management. For example, if there are observables that use and release some resource:and are composed into another observable:
the
finalize
calls will not do what you would expect, as the calls to release the sub-resources ina
andb
will happen after the release of the resource itself occurs inc
and - depending upon the resource - that can effect an error.Why the call order is weird without this change:
The order in which the callbacks are called is weird because the
finalize
operator adds the callback to theSubscription
:rxjs/src/internal/operators/finalize.ts
Lines 80 to 85 in dfa239d
It's added in the
Subscription
constructor, so the callback is the first teardown in the subscription. The subscription to the source is going to be added after that:rxjs/src/internal/operators/finalize.ts
Lines 70 to 72 in dfa239d
rxjs/src/internal/Observable.ts
Lines 212 to 222 in dfa239d
It's a breaking change:
Although the re-ordering of the
finalize
calls broke none of the existing tests, this is a breaking change, but it's a change for the better, IMO.Related issue (if exists): See #5372 and issues linked therein.