-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Added close handler on initial response for reactive SseEventSinkImpl #27707
Conversation
This comment has been minimized.
This comment has been minimized.
// // FIXME: notify of client closing | ||
// System.err.println("Server connection closed"); | ||
// }); | ||
response.addCloseHandler(() -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi!
I checked out your branch and was testing the solution but I cannot understand why the close handler is only added when !response.headWritten()
. Is this on purpose? For some reason, on my application this condition is always false and because of that the Close event firing never happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @rjvq85, thanks for taking a look!
No, this was not placed there with a specific purpose, I just added the closeHandler where the previous comment was, but it makes sense to move it out of the if statement, to always add it to the response.
For me the condition !response.headWritten()
was always true when testing, so it always execute the close handler, and I cannot reproduce a case where it gets evaluated to false... I used the reproducer provided by #23997, with the sse-server-reactive
module and it worked fine, the issues on the reactive server seemed to be resolved.
I tested again after moving the changes out of the if statement, and I don't see any unexpected behaviour, so i guess it's fine like that?
} | ||
response.addCloseHandler(() -> { | ||
if (broadcaster != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you should do this if
block since it's a part of close()
which you call anyway. Just call close()
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That works if the server is the one that closes the connection, the isClosed()
returns false
so the execution continues and broadcaster.fireClose(this)
at line 59 is actually called. When the client is the one that drops, isClosed()
method already returns true
when the closeHandler is executed and the broadcaster is never notified.
At least this was the case using the reproducer here (using reactive-server)
@@ -72,7 +72,9 @@ public synchronized void close() { | |||
|
|||
synchronized void fireClose(SseEventSinkImpl sseEventSink) { | |||
for (Consumer<SseEventSink> listener : onCloseListeners) { | |||
listener.accept(sseEventSink); | |||
if (sinks.remove(sseEventSink)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you removing the sink from the sinks? This will only match for the first listener, and subsequent listeners won't get called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get what do you mean, maybe I'm missing something. If we don't remove the sink (which is closing) from the broadcaster, that sink will continue to receive events even if it is closed, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have n
listeners. On the first one, you remove the sink, then it's removed, and for all remaining listeners the sink is already removed so you don't notify them. That's a logic bug, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, now I see it, sorry! You're right, the removal should happen after all the listeners have been notified. I'll convert this pr to draft and work some more on it, since I'm already adding some tests.
Also, could you add a test for this fix? |
Hi @FroMage, I added mockito as a dependency to do some tests, is it ok? |
Thanks. I'm generally in favour of real HTTP tests rather than Mockito. Do you think you could write a |
This comment has been minimized.
This comment has been minimized.
@a29340 any chance you could rebase and finalize this? I don't think we have fixed this issue already? |
@gsmet Yes, I will try to finalize this in the next few days. Sorry, I didn´t have a chance to work on it recently |
🎊 PR Preview 89fcdc9 has been successfully built and deployed to https://quarkus-io-pr-main-27707-preview.surge.sh/version/main/guides/ |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, could you rebase on the latest main
?
I'm moving this to draft again, some tests are still unstable (often they fail) when run on the CI pipeline on the forked branch. |
Hi @FroMage, sorry for the long wait. I finally did fix up the tests covering this PR, and rebased on the latest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late review. This is OK, except the byte-buddy dependency that should be aligned with the Quarkus BOM.
This comment has been minimized.
This comment has been minimized.
The first test failure seems related to this fix, no? |
Yes, looks like the test didn't detect the expected call on close method on the jdk 20 build. I'm trying to replicate on a local environment, but the tests pass every time. On the forked repo the jdk 11 build failed instead, with the same reason as this build, but passed on the 2nd attempt. Looks like it's not related to the specific java version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<type>pom</type> | ||
<scope>import</scope> | ||
</dependency> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need the BOM? Isn't adding the mockito test dependency enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually no, let me remove it. I'll try tu run the ci on the fork and then rebase
This comment has been minimized.
This comment has been minimized.
Hi @FroMage, I tried to replicate the same test failure on the fork ci for a while now, but couldn't find what was the issue. As of now the tests pass every time I run the ci on the fork. Can you please take a look at the tests in |
This comment has been minimized.
This comment has been minimized.
removed bom for mockito test dependency sorted imports removed colors and added logger instead of system out println formatted added more logs added more logs added more logs, updated bytebuddy formatted adding details to test log
✔️ The latest workflow run for the pull request has completed successfully. It should be safe to merge provided you have a look at the other checks in the summary. You can consult the Develocity build scans. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, all tests pass, you figured it out?
@FroMage No, the only thing I did was rebase and add logs, but for the last month or so I couldn't replicate the test failure. As of now the tests pass reliably, but I really don't know why they didn't before |
Well, we'll see if this occurs again. |
This pr adds the necessary handling of the close event on SseEventSinkIpl. This addresses the scenario when it is the client that is closing the connection, and the sink was not registering itself as closed and most importantly the broadcaster was never notified of the sink close state.