ffang commented on PR #3640:
URL: https://github.com/apache/cxf/pull/3640#issuecomment-6451495974
> Hi @ffang , I tested this solution against my camel reproducer and it
LGTM... all my attempts were good 💯 .
>
> Just out of curiosity, given your knowledge of the codebase, I wonder why
this particular problem showed up mainly in local test with wiremock ... and
it's occurring in production only to a very minor extent. My assumption of a
networks difference could be the cause for the race condition to happens more
frequently only in localhost... as I mentioned in the Jira ticket? I am a very
curious person :) . I tried debug further, but the game wasn't worth the candle
and didn't have much time.
>
> Thank, Valentino Porta
Hi @vp340,
Thanks for testing the fix against your Camel reproducer, and for confirming
it works. That's very helpful.
I think your network theory is right in spirit. It's a race between two
threads, so anything that changes their relative timing changes how often it
shows up.
With chunking disabled, CXF buffers the request and gives the `HttpClient` a
publisher that reports the buffered size. For an asynchronous call, two things
happen in parallel:
- **The caller thread** writes the body into the buffer and closes the
stream. Closing hands the response handling to the work queue without waiting,
then drops the buffer (`pout = null` and `publisher.close()`).
- **The `HttpClient` thread** gets a connection (a new one or a pooled one),
asks for the content length, writes the request headers, and only then
subscribes to the body.
In the old code, the body was sent only if the `HttpClient` finished all of
that before the caller dropped the buffer. If it was too late, it got either
`0/206` ("Too few bytes returned by the publisher") or a chunked request with
no body. Which thread wins depends on:
- whether the connection is new or reused, and the latency to open it;
- how long the headers take to write;
- how much of the body was already buffered when the send started;
- JIT warm-up;
- thread scheduling and load on the machine.
That fits what you saw. The first call is slow on the caller side (cold
JVM), so the `HttpClient` wins. Against a local WireMock everything after that
is warm and fast, so the caller wins every time. With a remote server or a
production network, the timing varies, so the outcome varies too. I haven't
measured exactly why your production setup lands at 0.01%, but I wouldn't read
too much into the exact numbers.
With this PR the publisher keeps its own reference to the buffered body, so
the order of the two threads no longer matters. Once it's in, you shouldn't
need `cxf-rt-transports-http-hc` or `AllowChunking=true` as a workaround.
Thanks,
Freeman
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]