Improving timeout and cancellation behaviour
arthurschreiber opened this issue · comments
Context
tedious
supports various forms of timeouts and cancellation behaviours:
- There's a connection level
connectTimeout
option that allows timing out the connection attempt if the connection does not get established after a specific amount of time. Such a timeout leads to the connection attempt to fail. - There's a connection level
requestTimeout
option that allows timing out aRequest
execution unless the request has been fully processed after a specific amount of time. Such a timeout leads to the request being either aborted before execution has started, or to the request being aborted while it is executing on the SQL Server. - Individual
Request
objects can becancelled
at any time during sending / execution phase to a similar effect as therequestTimeout
. - There's a connection level
cancelTimeout
option that aborts waiting for the request cancellation acknowledgement from the server after a request was cancelled (either due torequestTimeout
or an explicit request cancellation). This leads to the connection being closed and becoming unusable.
Problem description
There's multiple problems with how these timeouts are implemented and handled. Some of this has been previously described in #1100 with a focus on connect timeout behaviour, but these problems also exist for the other timeout types and the manual request cancellation behaviour.
To fix this properly, we should align all internal APIs to build their cancellation behaviour on top of AbortSignal
objects. Each asynchronous operation needs to accept a signal
argument. These signal
values need to be passed down correctly to all called
asynchronous functions.
All calls to await
need to honour AbortSignal
s by either using Promise.race
or by passing down the signal
to ensure that if the signal
is aborted, all computation immediately stops.
Task Breakdown - Code Areas that need to be updated with AbortSignal
support
-
StreamParser.parseTokens
-
RpcRequestPayload
and other that generate the payload in a streaming fashion. -
Connection.makeRequest
-
Connection.initialiseConnection
-
Connection.sendPreLogin
-
Connection.sendLogin7Packet
-
Connection.sendFedAuthTokenMessage
-
Connection.sendInitialSql
APIs exposed externally, like Connection.connect
or Connection.execSql
are out of scope of this work for now, but once all internal APIs have been wired up with AbortSignal
handling, it should be trivial to expose this externally.