@@ -220,7 +220,7 @@ interface Connection {
220
220
* - "pending": The Connection has been created but has not yet been established. Contributes to
221
221
* totalConnectionCount and pendingConnectionCount.
222
222
*
223
- * - "pending response": The Connection is attempting to discard a response for an operation where the socket timed
223
+ * - "pending response": The Connection is attempting to discard a response for an operation where the socket timed
224
224
* out. This state is only used when CSOT is enabled and maxTimeMS was added to the command.
225
225
*
226
226
* - "available": The Connection has been established and is waiting in the pool to be checked
@@ -358,7 +358,7 @@ interface ConnectionPool {
358
358
/**
359
359
* Mark all current Connections as stale, clear the WaitQueue, and mark the pool as "paused".
360
360
* No connections may be checked out or created in this pool until ready() is called again.
361
- * interruptInUseConnections specifies whether the pool will force interrupt "in use" connections as part of the clear.
361
+ * interruptInUseConnections specifies whether the pool will force interrupt "in use" connections as part of the clear.
362
362
* Default false.
363
363
*/
364
364
clear(interruptInUseConnections : Optional <Boolean >): void ;
@@ -579,7 +579,7 @@ other threads from checking out [Connections](#connection) while establishing a
579
579
Before a given [ Connection] ( #connection ) is returned from checkOut, it must be marked as "in use", and the pool's
580
580
availableConnectionCount MUST be decremented.
581
581
582
- ##### Awaiting Pending Read (CSOT-only )
582
+ ##### Awaiting Pending Read (drivers that support CSOT)
583
583
584
584
If an operation times out the socket while awaiting a server response and CSOT is enabled and ` maxTimeMS ` was added to
585
585
the command:
@@ -597,12 +597,12 @@ consuming buffered data.
597
597
1 . ** Persist and update timestamp** : The connection must record the current time immediately after the original socket
598
598
timeout. This timestamp MUST be updated to the current time whenever any bytes are successfully read, received, or
599
599
consumed while explicitly awaiting the pending response as part of checking out the connection.
600
- 2 . ** Aliveness check** : If the connection remains idle (i.e. no data is read or received) for more than 3 seconds since
601
- the start of the "pending response" state or since the last successful read/receive, the driver MUST attempt to
602
- verify the connection’s health by either performing a non-blocking read or using the minimal possible timeout to
603
- check if at least one byte can be read/received. If at least one byte can be read the connection should be returned
604
- to the pool for reuse and a retryable error should be propagated to the operation layer. If no bytes can be read,
605
- the connection MUST be closed.
600
+ 2 . ** Aliveness check** : If the undrained connection remains idle (i.e. no data is read or received) for more than 3
601
+ seconds since the start of the "pending response" state or since the last successful read/receive, the driver MUST
602
+ attempt to verify the connection’s health by either performing a non-blocking read or using the minimal possible
603
+ timeout to check if at least one byte can be read/received. If at least one byte can be read the connection should
604
+ be returned to the pool for reuse and a retryable error should be propagated to the operation layer. If no bytes
605
+ can be read, the connection MUST be closed.
606
606
3 . ** User-provided timeout** : If a user-provided timeout is specified for the "pending response" drain, the driver MUST
607
607
use the minimum of (a) the remaining time before the 3 second "pending response" window elapses and (b) the
608
608
user-provided timeout as the effective timeout for the read/drain operation.
@@ -618,76 +618,76 @@ consuming buffered data.
618
618
``` mermaid
619
619
sequenceDiagram
620
620
participant Driver
621
- participant Pool
622
- participant Conn as Connection (*)
623
- participant Server
624
-
621
+ participant Pool
622
+ participant Conn as Connection (*)
623
+ participant Server
624
+
625
625
Driver->>Pool: Checkout Connection (*)
626
626
Pool->>Driver: Return connection (*)
627
- Driver->>Conn: Send operation (1) (CSOT enabled, maxTimeMS > 0, exhaustAllowed = false)
628
- Conn->>Server: Send command
627
+ Driver->>Conn: Send operation (1) (CSOT enabled, maxTimeMS > 0, exhaustAllowed = false)
628
+ Conn->>Server: Send command
629
629
Server-->>Conn: (No response, socket times out)
630
630
631
- Conn->>Conn: Transition connection to "pending response" state, record current time
632
- Conn-->>Driver: Error
631
+ Conn->>Conn: Transition connection to "pending response" state, record current time
632
+ Conn-->>Driver: Error
633
633
634
634
Driver->>Pool: Checkout Connection (*)
635
635
Pool->>Driver: Return connection (*)
636
636
Driver->>Conn: Send operation (2)
637
-
637
+
638
638
Conn->>Conn: Attempt to drain pending response from operation (1)
639
- Conn->>Conn: Update pending read timestamp if bytes read
640
- alt Timeout window exceeded or non-timeout error
641
- Conn->>Conn: Close connection
642
- Conn-->>Driver: Error
643
- else Timeout window not exceeded
644
- alt Error
639
+ Conn->>Conn: Update pending read timestamp if bytes read
640
+ alt Timeout window exceeded or non-timeout error
641
+ Conn->>Conn: Close connection
642
+ Conn-->>Driver: Error
643
+ else Timeout window not exceeded
644
+ alt Error
645
645
Conn->>Conn: Clear pending response state
646
- Conn->>Conn: Reset to current time
647
- Conn->>Pool: Check connection back into pool
648
- Conn-->>Driver: Error
649
- else No error
650
- Conn->>Conn: Clear pending response state
651
- Conn->>Driver: Return connection to execute operation
652
- end
653
- end
646
+ Conn->>Conn: Reset to current time
647
+ Conn->>Pool: Check connection back into pool
648
+ Conn-->>Driver: Error
649
+ else No error
650
+ Conn->>Conn: Clear pending response state
651
+ Conn->>Driver: Return connection to execute operation
652
+ end
653
+ end
654
654
```
655
655
656
656
``` python
657
- PENDING_RESPONSE_TIMEOUT_MS = 3000 # static timeout
658
-
659
- def await_pending_response (timeout , conn ):
660
- # Note: conn.pending_start is initialized after the original socket timeout
661
- # and not in this function since the connection will sit in the pool for some
662
- # non-deterministic amount of time after the socket timeout.
663
-
664
- remaining_time = (conn.pending_start + PENDING_RESPONSE_TIMEOUT_MS ) - current_time()
665
- if remaining_time <= 0 :
666
- # Use the smallest timeout (or enable non-blocking read).
667
- remaining_time = 0.001
668
-
669
- if timeout is None :
670
- timeout = min (remaining_time, conn.socket_timeout_ms)
671
- else :
672
- timeout = min (remaining_time, timeout)
673
-
674
- data, error = execute_pending_response(timeout, conn)
675
- end_time = current_time()
676
-
677
- if error is not None and error is not timeout:
678
- close_connection(conn)
679
- raise
680
-
681
- if len (data) > 0 :
682
- # Refresh the remaining time upon a successful read
683
- conn.pending_start = end_time
684
-
685
- # Check if the remaining time has been exceeded
686
- if end_time - conn.pending_start >= PENDING_RESPONSE_TIMEOUT_MS :
687
- close_connection(conn)
688
-
689
- if error is not None :
690
- raise error
657
+ PENDING_RESPONSE_TIMEOUT_MS = 3000 # static timeout
658
+
659
+ def await_pending_response (timeout , conn ):
660
+ # Note: conn.pending_start is initialized after the original socket timeout
661
+ # and not in this function since the connection will sit in the pool for some
662
+ # non-deterministic amount of time after the socket timeout.
663
+
664
+ remaining_time = (conn.pending_start + PENDING_RESPONSE_TIMEOUT_MS ) - current_time()
665
+ if remaining_time <= 0 :
666
+ # Use the smallest timeout (or enable non-blocking read).
667
+ remaining_time = 0.001
668
+
669
+ if timeout is None :
670
+ timeout = min (remaining_time, conn.socket_timeout_ms)
671
+ else :
672
+ timeout = min (remaining_time, timeout)
673
+
674
+ data, error = execute_pending_response(timeout, conn)
675
+ end_time = current_time()
676
+
677
+ if error is not None and error is not timeout:
678
+ close_connection(conn)
679
+ raise
680
+
681
+ if len (data) > 0 :
682
+ # Refresh the remaining time upon a successful read
683
+ conn.pending_start = end_time
684
+
685
+ # Check if the remaining time has been exceeded
686
+ if end_time - conn.pending_start >= PENDING_RESPONSE_TIMEOUT_MS :
687
+ close_connection(conn)
688
+
689
+ if error is not None :
690
+ raise error
691
691
```
692
692
693
693
##### Pseudocode
@@ -966,7 +966,7 @@ interface PoolClosedEvent {
966
966
* Emitted when a Connection Pool creates a Connection object.
967
967
* NOTE: This does not mean that the Connection is ready for use.
968
968
*/
969
- interface ConnectionCreatedEvent {
969
+ interface ConnectionCreatedEvent {
970
970
/**
971
971
* The ServerAddress of the Endpoint the pool is attempting to connect to.
972
972
*/
@@ -1122,7 +1122,7 @@ interface ConnectionCheckedInEvent {
1122
1122
}
1123
1123
1124
1124
/**
1125
- * Emitted when the connection being checked out is attempting to read and
1125
+ * Emitted when the connection being checked out is attempting to read and
1126
1126
* discard a pending server response.
1127
1127
*/
1128
1128
interface PendingResponseStarted {
@@ -1143,7 +1143,7 @@ interface PendingResponseStarted {
1143
1143
}
1144
1144
1145
1145
/**
1146
- * Emitted when the connection successfully read the pending read and is ready
1146
+ * Emitted when the connection successfully read the pending read and is ready
1147
1147
* to be checked out.
1148
1148
*/
1149
1149
interface PendingResponseSucceeded {
@@ -1638,6 +1638,12 @@ Exhaust cursors are incompatible with the "pending response" connection state du
1638
1638
connection's completion, which occurs only when ` moreToCome=0 ` is received. Consequently, discarding one of these
1639
1639
responses does not restore the connection to a reusable state.
1640
1640
1641
+ ### Async IO Considerations for Awaiting a Pending Response
1642
+
1643
+ Several drivers (e.g., event-loop or background-read designs) perform socket I/O asynchronously. After a socket times
1644
+ out, the server's reply may be drained while the connection is idle in the pool. Therefore, the aliveness check only
1645
+ applies to an undrained connection that has exceeded the pending-response window without progress.
1646
+
1641
1647
## Backwards Compatibility
1642
1648
1643
1649
As mentioned in [ Deprecated Options] ( #deprecated-options ) , some drivers currently implement the options ` waitQueueSize `
0 commit comments