1_7_6.md

doc/release_notes/1_7_6.md

1.7.6

Improvements

  • datadog adapter: support setting custom peer.service.

  • stopped doing Thread.pass after checking connections back into the pool. The goal of this was to allow threads potentially waiting on a connection for the same origin to have the opportunity to take it before the same thread could check the same connection out, thereby preventing starvation on limited pool sizes; this however backfired for the common case of unbounded pool sizes (the default), and was specially bad when used for multiple concurrent requests on multiple origins, where avoidable lag was introduced on the whole processing every time a connection was checked back in. Thereby, the initial problem needs to be solved at the mutex implementation of CRuby.

  • connection: after keep alive timeout expired, try writing PING frame to the socket as soon as it’s emitted (previously, the frame was being buffered and the socket would be probed for readiness before writing it, whereas in most cases this is avoidable).

Bugfixes

  • reuse the same resolver instance when resolving multiple concurrent requests in the same option (it was previously instantiating different ones based on option heuristics, such as when requests had different :origin).

  • on successful early name resolution (from cache or hosts file, for example), check the resolver back to the pool (the object was being dereferenced).

  • http1 parser: turn buffer back into a string on reset, instead of preserving its current type (in cases where it was a chunked transfer decoder and connection was kept-alive, it was keeping it around and using it to parse the next request, which broke).

  • http1 parser: enable pipelining based on the max concurrent requests, which the connection may have had pre-set to 1 based on prior knowledge of origin or other heuristics.

  • http1 parser: when disabling pipelining, mark incomplete inlined requests as idle before sending them back to the pending queue.

  • http1 and http2 parser: remove references to requests escalating an error; in scenarios of connection reuse (such as when using the :persistent plugin), these requests could be, on a transition to idle state, resent even in the absence of an external session reference, causing avoidable overhead or contention leading to timeouts or errors.

  • connection: rescue and ignore exceptions when calling OpenSSL::SSL::SSLSocket#close or Socket#close.

  • connection: when sending multiple requests into an open HTTP/2 connection which keep alive may have expired, only a single (instead of multiple, as before) PING frame will be sent (in the prior state, only the first PING was being acknowledged, which made the connection accumulate unacknowledged ping payloads).

  • connection: on handling errors, preventing potential race condition by copying pending requests into a local var before calling parser.handle_error (this may trigger a callback which calls reset, which may call disconnect, which would check the connection back into the pool and make it available for another thread, which could change the state of the ivar containing pending requests).

  • connection: skip resetting a connection when idle and having pending requests; this may happen in situation where parsers may have reset-and-back-to-idle the connection to resend failed requests as protocol (such as in the case of failed HTTP/1 pipelinining requests where incomplete requests are to be resent to the connection once pipelining is disabled).

  • connection: raise request timeout errors for the request the connection is currently in, instead of the connection where it was initially sent on and set timeouts on; this happens in situations where the request may be retried and sent to a different connection, which forces the request to keep a reference to the connection it’s currently in (and discard it when it no longer needs it to prevent it from being GC’ed).

  • :auth plugin: when used alongside the :retries plugin for multiple concurrent requests, it was calling the dynamic token generator block once for each request; fixed to call the block only once per retry window, so retrying requests will reuse the same.

  • :retries plugin: retry request immediately if :retry_after is negative (while the option is validated for numbers, it can’t control proc-based calculation).