After the query-in-flight sub-state machine refactoring (#67), the ReadyForQuery(non-idle) double-delivery is fixed. However, a separate double-delivery window remains due to _process_again.
_ResponseMessageParser processes one message per call, then schedules s._process_again() (a behavior call) to process the next buffered message. This creates a scheduling window between consecutive messages where other behaviors can execute:
ErrorResponse arrives — on_error_response delivers the error to the receiver
_process_again is scheduled as a behavior call
close() behavior executes before _process_again — on_shutdown iterates the queue and sends SessionClosed to the same receiver (double delivery)
_process_again would have processed ReadyForQuery and dequeued, but it's too late
This is a pre-existing issue (present before #67) and affects any pair of messages where the first delivers a result/error and the second dequeues the query.
After the query-in-flight sub-state machine refactoring (#67), the
ReadyForQuery(non-idle)double-delivery is fixed. However, a separate double-delivery window remains due to_process_again._ResponseMessageParserprocesses one message per call, then scheduless._process_again()(a behavior call) to process the next buffered message. This creates a scheduling window between consecutive messages where other behaviors can execute:ErrorResponsearrives —on_error_responsedelivers the error to the receiver_process_againis scheduled as a behavior callclose()behavior executes before_process_again—on_shutdowniterates the queue and sendsSessionClosedto the same receiver (double delivery)_process_againwould have processedReadyForQueryand dequeued, but it's too lateThis is a pre-existing issue (present before #67) and affects any pair of messages where the first delivers a result/error and the second dequeues the query.