Sdk: StreamSubscription.cancel should fire the onDone callback

Created on 9 Mar 2013  路  4Comments  路  Source: dart-lang/sdk

Currently, if a StreamSubscription is cancelled, there's no way for the callbacks listening on that subscription to know that it's been cancelled. A listener that's been cancelled is indistinguishable from a stream that's just taking a long time to emit its next value. This makes it easy for programmers to accidentally insert deadlocks in their code were an unsubscription causes a listener to wait forever.

I think the best solution here is to make StreamSubscription.cancel send an onDone event, as though the stream itself had closed.

The same issues are also present when unsubscribeOnError is set to true.

P2 area-library core-n library-async type-enhancement

Most helpful comment

Encountered this issue as well. Initial thought was that my broadcasted stream's source was not ending the stream properly when there was no more subscribers (as it was supposed to).

I think this behaviour can look like a bug for newcomers to dart streams like me, and should be documented on cancel() and/or onDone().

All 4 comments

It's expected that the code calling listen, adding event handlers and calling cancel is the same unit, so it should be possible to know if cancel is called, or if an error event occurs when unsubscribeOnError is set.
What you are asking for is a kind of "onUnsubscription" callback that is called no matter how the subscription stops subscribing (cancel, after a done event, or after an error event if unsubscribing-on-error). Using the "done" event for that would be mixing concepts.
It should be fairly simple to make an adapter for a subscription that allows this, so I'm not sure we would want to add it to the base subscription.


_Removed Type-Defect label._
_Added Type-Enhancement label._

It's expected that the code calling listen, adding event handlers and calling cancel is the same unit, so it should be possible to know if cancel is called, or if an error event occurs when unsubscribeOnError is set.
What you are asking for is a kind of "onUnsubscription" callback that is called no matter how the subscription stops subscribing (cancel, after a done event, or after an error event if unsubscribing-on-error). Using the "done" event for that would be mixing concepts.

I don't think it's realistic to assume that cancellation occurs in the same code unit as subscription. The Stream API is built with chaining and transformation in mind, which means that downstream listeners need a way of being notified that the upstream Stream has stopped firing events. I don't think firing onDone is mixing concepts, I think it means exactly "this stream has finished firing events".

For some background, the reason this came up for me was a method I wrote with the signature "Pair<Stream, StreamSubscription> streamWithSubscription(Stream)". It wrapped a Stream and returned a StreamSubscription to control the wrapped stream. I expected that calling cancel on the subscription would close the returned Stream, and ran into bugs when it didn't.

It should be fairly simple to make an adapter for a subscription that allows this, so I'm not sure we would want to add it to the base subscription.

dart:async currently provides no help for implementing a StreamSubscription with custom behavior, so it would actually be reasonably difficult to do this right now.

I no longer need this behavior.

Encountered this issue as well. Initial thought was that my broadcasted stream's source was not ending the stream properly when there was no more subscribers (as it was supposed to).

I think this behaviour can look like a bug for newcomers to dart streams like me, and should be documented on cancel() and/or onDone().

Was this page helpful?
0 / 5 - 0 ratings