Because onResponse(response) decrements ongoing prematurely (before submitting the response and potentially completing downstream), the last response passed might be missed when a race happens with onInitialResponseBodyCompletion(). Consider this scenario:
onResponse acquires the lock first, and decrements ongoing. It won't perceive initial body completion, so it won't want to complete downstream.
onInitialResponseBodyCompletion acquires the lock later, and perceives no ongoing responses, so it proceeds with the intent to complete downstream.
onInitialResponseBodyCompletion continues, and calls complete(), which pushes the sentinel to the queue.
onResponse continues to submit(response), but the response is submitted after the sentinel and is hence ignored.
The fix is to not prematurely decrement ongoing when the last response is received, but do so after the response is submitted. This way, onInitialResponseBodyCompletion never perceives a completed stream that is not really completed.
coverage: 91.309% (+0.006%) from 91.303%
when pulling 790bdddc63b89c13f578350d37386718ec50ab4b on fix-missed-response
into e77b44d5552de7d042bd6e9c63d26bd122904477 on master.
Because
onResponse(response)
decrementsongoing
prematurely (before submitting the response and potentially completing downstream), the last response passed might be missed when a race happens withonInitialResponseBodyCompletion()
. Consider this scenario:onResponse
&onInitialResponseBodyCompletion
interleave.onResponse
acquires the lock first, and decrementsongoing
. It won't perceive initial body completion, so it won't want to complete downstream.onInitialResponseBodyCompletion
acquires the lock later, and perceives no ongoing responses, so it proceeds with the intent to complete downstream.onInitialResponseBodyCompletion
continues, and callscomplete()
, which pushes the sentinel to the queue.onResponse
continues tosubmit(response)
, but the response is submitted after the sentinel and is hence ignored.The fix is to not prematurely decrement
ongoing
when the last response is received, but do so after the response is submitted. This way,onInitialResponseBodyCompletion
never perceives a completed stream that is not really completed.