node-mssql icon indicating copy to clipboard operation
node-mssql copied to clipboard

Feature Request: Request.prototype.setTimeout()

Open fullsailor opened this issue 10 months ago • 4 comments

I need a way to set different request timeouts without using multiple connection pools. Tedious has a setTimeout function on Request that implements this behavior, but there's not a defined way to get at the driver Request object from a mssql.Request object.

Expected behaviour:

That I could have a pool and request like this, and that the specified timeout would be set on the underlying tedious Request when it is created.

const pool = new ConnectionPool({options: { requestTimeout: 15_000 });
await pool.request().setTimeout(90_000).query("waitfor delay '00:01'"); // synthetic slow query

Actual behaviour:

The only supported workaround is to have different connection pools with different timeouts. This works in some limited cases, but is not very flexible and we can't have two requests in the same transaction with different timeouts.

Software versions

  • NodeJS: 18
  • node-mssql: 9.1.1
  • SQL Server: 2019

Monkey patch

A bad implementation of this feature would be something like this patch.

declare module 'mssql' {
    interface Request {
        setTimeout(timeout: number | undefined): this;
    }
}

const kTimeout = Symbol('request timeout');
Request.prototype.setTimeout = function (timeout: number | undefined) {
    this[kTimeout] = timeout;
    // for chaining like other mssql Request functions
    return this;
};

// _setCurrentRequest is the only 'hook' that we can patch to get at the underlying
// tedious request before it is passed to the acquired connection
const orig = Request.prototype._setCurrentRequest as (req: any) => any;
Request.prototype._setCurrentRequest = function _setCurrentRequest(req: tedious.Request) {
    if (this[kTimeout] !== undefined) {
        req.setTimeout(this[kTimeout] as number);
    }
    return orig.call(this, req);
};

fullsailor avatar Aug 16 '23 13:08 fullsailor