I got a report today that the `ioReactorExceptionCallback` is firing due to
a socket timeout:

java.net.SocketTimeoutException: 2500 MILLISECONDS
at
org.apache.hc.core5.io.SocketTimeoutExceptionFactory.create(SocketTimeoutExceptionFactory.java:50)
at
org.apache.hc.core5.reactor.ssl.SSLIOSession$1.timeout(SSLIOSession.java:223)
at
org.apache.hc.core5.reactor.InternalDataChannel.onTimeout(InternalDataChannel.java:170)
at
org.apache.hc.core5.reactor.InternalChannel.checkTimeout(InternalChannel.java:67)
at
org.apache.hc.core5.reactor.SingleCoreIOReactor.checkTimeout(SingleCoreIOReactor.java:239)
at
org.apache.hc.core5.reactor.SingleCoreIOReactor.validateActiveChannels(SingleCoreIOReactor.java:166)
at
org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:128)
at
org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:92)
at org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44)
at java.base/java.lang.Thread.run(Thread.java:840)

Based on the code and the stack trace, 2500 milliseconds is actually the
connection timeout and thus the TLS handshake timeout. This is reproducible
in TestAsyncTlsHandshakeTimeout by setting `HttpVersionPolicy.FORCE_HTTP_2`
(but _not_ `NEGOTIATE`). I traced this change in behavior back to the
following commit:

https://github.com/apache/httpcomponents-core/commit/be9902826576413c694c59cc582fc38db8aeb772

This is a regression, as the contract for `setIoReactorExceptionCallback()`
is that it sets a callback for exceptions that propagate all the way
through the IOReactor *and kill the client*. The default behavior
(cf. LoggingExceptionCallback) is to log an ERROR, which is bad enough, but
in our case we supply a custom callback that logs a FATAL, which then
triggers alarms and stuff.

How should we address this? What types of exceptions were intended to be
reported by be9902826? We probably (1) want to use a different exception
callback for these exceptions and (2) want to fire the callback only for
unexpected (internal) exceptions and not things like timeouts. It's also
possible that this exception callback should fire when
`HttpVersionPolicy.NEGOTIATE` is used; it currently doesn't, which may also
be a bug.

Reply via email to