-
Notifications
You must be signed in to change notification settings - Fork 37.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
Implement Eclipse Jetty core HTTP handler adapter #32097
base: main
Are you sure you want to change the base?
Conversation
@gregw Please sign the Contributor License Agreement! Click here to manually synchronize the status of this Pull Request. See the FAQ for frequently asked questions. |
@pivotal-cla Working on getting a CCLA signed. Stand by.... |
.../main/java/org/springframework/web/reactive/function/server/DefaultServerRequestBuilder.java
Outdated
Show resolved
Hide resolved
@lachlan-roberts can you sign the individual CLA. |
This PR is failing 2 tests that undertow also fails: See #25310. |
@gregw Thank you for signing the Contributor License Agreement! |
// TODO: Why does intellij warn about possible blocking call? | ||
// Because it can block and we want to be fully asynchronous. Use AsynchronousFileChannel | ||
SeekableByteChannel channel = Files.newByteChannel(file, StandardOpenOption.READ); |
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.
Files.newByteChannel
is a blocking operation, but I see that undertow also use it and just live with the warning. The chance of it actually blocking for any significant time is vanishingly small and there is no chance of dead lock.
// this.dataBuffer = dataBufferFactory.wrap(BufferUtil.copy(chunk.getByteBuffer())); // TODO this copy avoids multipart bugs | ||
this.dataBuffer = dataBufferFactory.wrap(chunk.getByteBuffer()); // TODO avoid double slice? |
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.
This is the work around for the failing multipart tests (see #25310)
...g-web/src/main/java/org/springframework/http/server/reactive/JettyCoreServerHttpRequest.java
Outdated
Show resolved
Hide resolved
...g-web/src/main/java/org/springframework/http/server/reactive/JettyCoreServerHttpRequest.java
Outdated
Show resolved
Hide resolved
...g-web/src/main/java/org/springframework/http/server/reactive/JettyCoreServerHttpRequest.java
Outdated
Show resolved
Hide resolved
…pResponse Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
…HttpResponse Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
Signed-off-by: Lachlan Roberts <lachlan.p.roberts@gmail.com>
Update spring Jetty websocket usage
@gregw Hi Greg, sorry for the recent lack of feedback. I plan to take a look at this PR soon, and hopefully we can merge it in 6.2 M2 or M3. |
@poutsma Would be good to get at least an initial review, as I'm sure there is some rough edges that need to be knocked off. Giving us a few comments will get us working on this and updating... plus we want to flow the work through springboot as well. |
@gregw Fair point. I had to take some unforeseen medical leave, but plan to focus on this PR this coming week. |
@gregw First off, thank you for submitting this PR, as well as your patience with regards to us handling it. The PR seems to be quite usable, and I am sure it will make it into 6.2. Before getting into any specific details, my main question is why do How should we proceed? If you prefer, I can take the PR from here, and get back you when I have questions. Or I can provide a more thorough review. |
Awesome!
Very good question. I cannot recall and looking at the code now, I see no particular reason, at least not for the request.
I'm flexible. I think it would be good to get you closely involved as I'm sure there a spring things that I'm doing wrong and working together would be a good way to communicate knowledge. So how about this as an approach:
|
Signed-off-by: Lachlan Roberts <lachlan.p.roberts@gmail.com>
Signed-off-by: Lachlan Roberts <lachlan.p.roberts@gmail.com>
Sounds good to me. It looks like you committed step 1 (d6986ee), so I will get started with step 2. Unless there are more changes forthcoming? |
@poutsma my step 1 is pretty broken. I think it need more work. stand by.... |
upgrade jetty
@poutsma I've backed out the abstract response changes for now, as they broke a lot of tests. So I need to understand the difference and try again. Probably tomorrow now... |
…dapter # Conflicts: # framework-platform/framework-platform.gradle
Signed-off-by: Lachlan Roberts <lachlan.p.roberts@gmail.com>
@poutsma OK I think I've cracked the abstract response now as well. There is one test that fails occasionally that I need to look into more, but I think the PR is good for you to look at now. If you want to start making changes, go for it.. or direct me. |
…erAdapter' into JettyCoreHttpHandlerAdapter
@gregw I have made a first pass at reviewing the PR, and so far have made two changes:
Regardless of whether the changes above have been applied, the main test failure I see is |
I have committed several other changes, see https://github.com/poutsma/spring-framework/commits/gh-32097/. The only test that fails is the
@gregw Does that ring any bell with you, or are we doing something wrong in the Spring code? I have also asked @rstoyanchev and @simonbasle to review (my branch of) the PR, so comments from them might be forthcoming. The next Spring Framework milestone (6.2.0-M4) is on June 13th. I am not sure if we will have resolved the test above by that point, so this PR might not make that milestone. The milestone after that is scheduled for July 11th. |
|
||
private final Flux<WebSocketMessage> flux; | ||
private final Sinks.One<CloseStatus> closeStatusSink = Sinks.one(); | ||
private final Lock lock = new ReentrantLock(); |
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.
This Lock
got my attention because pessimistic locking is usually not the first go-to method in Reactive Streams. Instead it's usually some sort of optimistic locking with a CAS loop.
That said, the lock protects 2 critical sections that represent quick state checks and updates. There is precedent for that sort of things, e.g. in Reactor
, so in that case I think it is fine (although care will need to be exercised if the code is modified or new usage of the lock is introduced).
boolean demand = false; | ||
this.lock.lock(); | ||
try { | ||
this.requested += n; |
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.
this is more problematic, as n
can be an "unbounded request" (Integer.MAX_VALUE
) and this.requested
can overflow to negative.
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.
this.requested += n; | |
this.requested += n; | |
if (this.requested < 0L) { | |
this.requested = Long.MAX_VALUE; | |
} |
try { | ||
this.requested += n; | ||
if (!this.awaitingMessage && this.requested > 0) { | ||
this.requested--; |
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'm not entirely sure how it translates in terms of getDelegate().demand()
calls, but if the requested amount is unbounded, this decrement shouldn't happen.
with the above suggested change, unbounded request amount (n == Integer.MAXVALUE
at any point) leads to this.requested == Long.MAX_VALUE
so if that's the case the this.requested--
decrement should be skipped.
} | ||
this.awaitingMessage = false; | ||
if (this.requested > 0) { | ||
this.requested--; |
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.
same as above, this should take the "unbounded request" scenario (in the Reactive Streams sense) into consideration
This provides an implementation of a HTTP Handler Adaptor that is coded directly to the Eclipse Jetty core API, bypassing any servlet implementation.
Fixes #32035