Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single onCancel and OnComplete fixes #1814

Merged
merged 3 commits into from
May 23, 2020

Conversation

danielkec
Copy link
Contributor

Thx @olotenko for finding the issue
Signed-off-by: Daniel Kec daniel.kec@oracle.com

Signed-off-by: Daniel Kec <daniel.kec@oracle.com>
Copy link

@olotenko olotenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an unsatisfactory change.

If a 5-minute drive-by review finds 3 issues, what else is lurking?

What makes the rewrite of the entire CompletableFuture necessary in the first place? Its operation and contract is subtle.

Type-wise problem:

Default Single.onCancel creates a new Single and was probably designed for builder-like flowing style. A subtype of Single now mutates this. Case in point: the very invocation of single.onCancel from inside onSubscribe is invalid; it only works as long as Single.from returns a specific subtype of Single. When that changes, this implementation will be broken and you will never find out why.

Atomicity:

On at least one path multiple things are modified, but not atomically. This is going to create problems in valid use cases. Case in point: multiple Subscriber will be created and subscribed, and will not make any progress, thus breaking the reactive spec that the Subscriber s eventually either cancel or request.

Deferred action:

Cancellation is deferred until onCancel is registered. (Ok, this one is addressed)

In order to justify a deep analysis of the change (#1664), I would like to see a justification for a rewrite in that pull request.

@tomas-langer
Copy link
Member

Why did we rewrite Single as an implementation of CompletionStage:

  1. Single is a promise of a single value, most of reactive implementations treat this as a specific Flow.Publisher case, yet it is a CompletionStage that can act as a publisher as well
  2. Lot of implementation do not handle Flow (or it is too complicated to handle subscribers) for Single cases - a lot of times the API of CompletionStage is more suitable to implement desired functionality
  3. Helidon APIs now have a single method, and it is a choice of user whether to use Single, Flow.Publisher or CompletionStage for a promise of a single unit. This makes the design and used of the API much easier, as before we needed to call additional methods

Signed-off-by: Daniel Kec <daniel.kec@oracle.com>
…issing onComplete callbacks

Signed-off-by: Daniel Kec <daniel.kec@oracle.com>
@danielkec danielkec changed the title Register cancel callback before requesting Single onCancel and OnComplete fixes May 20, 2020
@danielkec danielkec added the reactive Reactive streams and related components label May 21, 2020
@danielkec danielkec self-assigned this May 21, 2020
@danielkec danielkec added this to the 2.0.0 milestone May 21, 2020
@danielkec danielkec merged commit 53f79a4 into helidon-io:master May 23, 2020
Copy link

@olotenko olotenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How could it have "missed" onComplete? It cannot transition to any new state after super.complete, even if upstream decides to onError. Besides, the atomic getAndSet will transition to yet another state where the onComplete is futile, even if observed.

@danielkec
Copy link
Contributor Author

@olotenko There is no onComplete signal coming from publisher if you send cancel from onNext

@olotenko
Copy link

So?

@danielkec
Copy link
Contributor Author

Single.just("a").onComplete(()-> this is missed).await() commit message mentions operator onComplete not the subscriber's method

@olotenko
Copy link

olotenko commented May 24, 2020

You've just shown yet another problem with this design where both CompletionStage and Subscriber contracts overlap. Exactly what I told you offline.

Requesting cancellation is legitimate. Anyone who has access to Single or any other part of the pipeline can do that. If this breaks await, the design is wrong.

The problem with me enumerating what can go wrong is that it seems the specific symptoms get addressed, not the underlying design problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
reactive Reactive streams and related components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants