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

Issue #11803 - Follow Reactive Streams specification #11804

Closed
wants to merge 17 commits into from

Conversation

scrat98
Copy link
Contributor

@scrat98 scrat98 commented May 16, 2024

The main improvements:

  • safely close resources in case of any errors to avoid resource leaks
  • multi-threaded reading from Content.Source is avoided
  • more accurate implementation of Reactive Streams and passed TCK tests

// As per rule 3.13, Subscription.cancel() MUST request the Publisher to eventually
// drop any references to the corresponding subscriber.
this.demand.set(NO_MORE_DEMAND);
// TODO: HttpChannelState does not satisfy the contract of Content.Source "If read() has returned a last chunk, this is a no operation."
Copy link
Contributor Author

@scrat98 scrat98 May 16, 2024

Choose a reason for hiding this comment

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

HttpChannelState does not satisfy the contract of Content.Source.fail method "If read() has returned a last chunk, this is a no operation."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@@ -50,6 +55,22 @@
<argLine>@{argLine} ${jetty.surefire.argLine}
--add-reads org.eclipse.jetty.io=org.eclipse.jetty.logging</argLine>
</configuration>
<dependencies>
<!--
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's ugly, but maybe I could:

  • Create pull request to the reactive streams TCK and support also junit platform
  • Have a look at the surefire plugin and try to understand if it possible to make junit5 with testng working together out of the box

Copy link
Contributor

Choose a reason for hiding this comment

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

@olamy ???

Copy link
Member

Choose a reason for hiding this comment

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

yup no much choice.

Copy link
Member

Choose a reason for hiding this comment

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

It would be good to add parsing of testng result files for Jenkins.

olamy@pop-os:~/dev/sources/jetty/jetty.project$ ls -lrt jetty-core/jetty-io/target/surefire-reports/Surefire\ suite/
total 72
-rw-rw-r-- 1 olamy olamy 60957 May 22 12:43 'Surefire test.html'
-rw-rw-r-- 1 olamy olamy  7951 May 22 12:43 'Surefire test.xml'
-rw-rw-r-- 1 olamy olamy  2127 May 22 12:43  testng-failed.xml

See the Jenkinsfille
transform

junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml', allowEmptyResults: true

into

junit testResults: '**/target/surefire-reports/**/*.xml,**/target/invoker-reports/TEST*.xml', allowEmptyResults: true

This should make it (at least we will see :))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@olamy if you have time, could you please update jenkins configuration, because I'm not so much familiar with it

Copy link
Member

Choose a reason for hiding this comment

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

I cannot push to your fork/branch. So you will need to cherry pick this commit 5f0168b

Copy link
Contributor Author

@scrat98 scrat98 Jun 4, 2024

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Is this new testng requirement because it's used by import import org.reactivestreams.tck.TestEnvironment; ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@joakime unfortunately yes https://github.com/reactive-streams/reactive-streams-jvm/tree/master/tck

I'm not a fun to mix multiple testing frameworks, but it is what it is

Copy link
Contributor

@gregw gregw left a comment

Choose a reason for hiding this comment

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

Thanks for this... looks good, but will need careful review. Just a couple of trivial comments first whilst I find time to look deeper....

@gregw gregw requested review from sbordet and lorban May 21, 2024 22:14
Copy link
Contributor

@gregw gregw left a comment

Choose a reason for hiding this comment

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

More feedback...

pom.xml Show resolved Hide resolved
pom.xml Show resolved Hide resolved
pom.xml Outdated Show resolved Hide resolved
pom.xml Outdated Show resolved Hide resolved
pom.xml Outdated Show resolved Hide resolved
pom.xml Show resolved Hide resolved
@@ -50,6 +55,22 @@
<argLine>@{argLine} ${jetty.surefire.argLine}
--add-reads org.eclipse.jetty.io=org.eclipse.jetty.logging</argLine>
</configuration>
<dependencies>
<!--
Copy link
Member

Choose a reason for hiding this comment

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

It would be good to add parsing of testng result files for Jenkins.

olamy@pop-os:~/dev/sources/jetty/jetty.project$ ls -lrt jetty-core/jetty-io/target/surefire-reports/Surefire\ suite/
total 72
-rw-rw-r-- 1 olamy olamy 60957 May 22 12:43 'Surefire test.html'
-rw-rw-r-- 1 olamy olamy  7951 May 22 12:43 'Surefire test.xml'
-rw-rw-r-- 1 olamy olamy  2127 May 22 12:43  testng-failed.xml

See the Jenkinsfille
transform

junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml', allowEmptyResults: true

into

junit testResults: '**/target/surefire-reports/**/*.xml,**/target/invoker-reports/TEST*.xml', allowEmptyResults: true

This should make it (at least we will see :))


public ContentSourcePublisher(Content.Source content)
{
this.content = content;
if (content == null)
Copy link
Contributor

Choose a reason for hiding this comment

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

Better use Objects.requireNonNull(content)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@lorban thank you, fixed

// As per rule 2.13, we MUST consider subscription cancelled and
// MUST raise this error condition in a fashion that is adequate for the runtime environment.
subscription.cancel(err, LastWillSubscription.FinalSignal.SUPPRESS);
LOG.error("Flow.Subscriber " + subscriber + " violated rule 2.13", err);
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't it be better to rethrow rather than logging?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@lorban According to the specification we cannot throw any exception

  1. As per rule 1.9, subscribe method must return normally (i.e. not throw)
  2. As per rule 2.13, ...the caller MUST raise this error condition in a fashion that is adequate for the runtime environment. «Raise this error condition in a fashion that is adequate for the runtime environment» could mean logging the error—or otherwise make someone or something aware of the situation—as the error cannot be signalled to the faulty Subscriber.

stalled = false;
process = true;
}
if (reason == null)
Copy link
Contributor

Choose a reason for hiding this comment

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

Better use Objects.requireNonNull()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@lorban thank you, fixed

content.fail(chunk.getFailure());
subscriber.onError(chunk.getFailure());
return;
LOG.error("Flow.Subscriber " + subscriber + " violated rule 2.13", err);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are you catching Throwable here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@lorban ActiveSubscription.process() method triggered from Subscription.cancel/request methods and may be executed synchronously

  • 3.10, 3.11 While the Subscription is not cancelled, Subscription.request(long n) MAY synchronously call onNext on this
  • 3.15 and 3.16 Calling Subscription.cancel/request MUST return normal (that's the reason why we cannot throw here)
  • 2.13, ...the caller MUST raise this error condition in a fashion that is adequate for the runtime environment. «Raise this error condition in a fashion that is adequate for the runtime environment» could mean logging the error—or otherwise make someone or something aware of the situation—as the error cannot be signalled to the faulty Subscriber.

catch (Throwable err)
{
cancel(err, FinalSignal.SUPPRESS);
LOG.error("Flow.Subscriber " + subscriber + " violated rule 2.13", err);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not rethrowing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@lorban the same reason as above

@gregw gregw requested review from gregw, lorban and olamy May 23, 2024 07:20
gregw added a commit that referenced this pull request May 28, 2024
Simplified #11804
 + removed LastWillSubscription, LastWill and FinalSignal
 + introduced Suppressed and Cancelled Throwables
 + updated notes
@gregw
Copy link
Contributor

gregw commented May 28, 2024

@scrat98 I thought you might be getting a bit tired of our exacting review process.... so I branched this in #11849 and changed it to how I'd like to see it. The key commit c216b00, which removes all the LastWill stuff, which I don't like for the name and for the additional complexity. Instead, I'm just using typed Throwables to signal the type of cancellation.

It passes the test.

Feel free to bring in that commit here if you wish to make further modifications and I'll close the other PR.

olamy pushed a commit that referenced this pull request May 29, 2024
Simplified #11804
 + removed LastWillSubscription, LastWill and FinalSignal
 + introduced Suppressed and Cancelled Throwables
 + updated notes
@scrat98
Copy link
Contributor Author

scrat98 commented May 30, 2024

@scrat98 I thought you might be getting a bit tired of our exacting review process.... so I branched this in #11849 and changed it to how I'd like to see it. The key commit c216b00, which removes all the LastWill stuff, which I don't like for the name and for the additional complexity. Instead, I'm just using typed Throwables to signal the type of cancellation.

It passes the test.

Feel free to bring in that commit here if you wish to make further modifications and I'll close the other PR.

No worries, I'm much appreciated for such review process :) Thank you a lot for your time, I'll have a look at your changes this weekends(I'm sorry don't have enough free time this week) and cherry pick them. But the general idea is clear, thanks again

gregw
gregw previously approved these changes Jun 4, 2024
Copy link
Contributor

@gregw gregw left a comment

Choose a reason for hiding this comment

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

I think this looks good to go. Would be good to get it merged early in a release cycle.
I think the CI failures are unrelated, but we should check

@scrat98
Copy link
Contributor Author

scrat98 commented Jun 5, 2024

I think this looks good to go. Would be good to get it merged early in a release cycle. I think the CI failures are unrelated, but we should check

Hi @gregw. If you don't mind let me day tomorrow, I would like to consider your changes as well and remove some todos from the code. I know that promised do it 2 days ago, but only tomorrow finally will have spare day to finish this merge request. Thanks in advance

@scrat98
Copy link
Contributor Author

scrat98 commented Jun 5, 2024

@gregw I think I'm done, one more time reviewed every comment and all changes. Small refactoring:

  • made LastWill COMPLETED static
  • mentioned about HttpChannelState issue. I tried to solve it, but seems I need more time to understand the code base
  • used fast path when this.subscriber.onNext(chunk) failed

About your suggested changes:

  1. "LastWill" naming
  • I borrowed that term from the mqtt protocol and I thought that's well known design pattern
  • It's not publicly available, but only private utility class. Therefore I think the chance that open source community will create holivars off-topics about it is very low
  1. "LastWill" abstraction
  • It should help think less while implementing RS specification. For example, you don't need to think if it Exhausted or Active subscription. The rule of thumb that subscription must always be cancelled. Also I like explicitly specify final state, it seems more natural look at all possible states in the enum rather than using instanceof and thinking about all possible subclasses.
  • It avoids creating wrapper of the Exception(like for suppressed exceptions) and just uses original exception as it is.

Nevertheless, I gave you full access to the fork, feel free to merge your changes, I'm absolutely okay with it.

About CI/CD tests it seems there are fluky tests, but this failed test I found really strange https://jenkins.webtide.net/job/jetty.project/job/PR-11804/20/testReport/org.eclipse.jetty.server/LoggerDebugTest/Parallel_Stage___Build___Test___JDK22___testWrapperNPE/

@gregw
Copy link
Contributor

gregw commented Jun 6, 2024

@scrat98 I have reopened by simplification of this in #11849. Not only do I not like the LastWill name, I don't think we even need that abstraction. I think my branch is meeting all the tests without it.
So my intention is to go forward with merging that PR once it is reviewed by others (you will still get author credit as it has your commits in the PR). I can't see anything in your latest changes that needs to be copied over... but please do check that branch.

thanks for this contribution.

scrat98 pushed a commit to scrat98/jetty.project that referenced this pull request Jun 6, 2024
Simplified jetty#11804
 + removed LastWillSubscription, LastWill and FinalSignal
 + introduced Suppressed and Cancelled Throwables
 + updated notes
@scrat98
Copy link
Contributor Author

scrat98 commented Jun 6, 2024

@gregw I prefer to merge your changes to this PR for the following reasons:

  • Keep tracking all comments in this PR
  • Preserve original git history
  • Keep changes about handling failure of this.subscriber.onNext(chunk) more properly and also comment about HttpChannelState issue
  • I think Cancellation exception not needed as it not used

So I have cherry-picked your commit c216b00. If it's okay, please merge scrat98#1

Update: merge last changes as well. The difference with 11849 (git diff contrib/11804/ReactiveStreamSpec jetty-12.0.x-11849):

  • comment about HttpChannelState issue
catch (Throwable err)
             {
+                chunk.release();
                 cancel(new SuppressedException(err));
                 if (LOG.isTraceEnabled())
                     LOG.trace("Flow.Subscriber " + subscriber + " violated rule 2.13", err);
+                return Action.IDLE;
             }
  • removed CancelledException

gregw added a commit that referenced this pull request Jun 13, 2024
* Issue #11803 - Follow Reactive Streams specification
* Simplification of #11804 for Reactive Stream specification support

---------

Co-authored-by: Artem Golovko <artemgolovko98@gmail.com>
Co-authored-by: Olivier Lamy <olamy@apache.org>
@gregw
Copy link
Contributor

gregw commented Jun 13, 2024

#11849 has been merged. Thanks so much @scrat98. Great work!

@gregw gregw closed this Jun 13, 2024
@scrat98 scrat98 mentioned this pull request Jul 9, 2024
50 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Status: ✅ Done
Development

Successfully merging this pull request may close these issues.

5 participants