Skip to content

oracledb.queueTimeout set to 0, but the queued connection requests are never terminated #1338

@menghu07

Description

@menghu07
  1. Oracle Version: Oracle 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
    Platform: win32
    Version: v12.13.1
    Arch: x64
    Version String: 5.0.0
    Client Version String: 12.1.0.2.0

  2. When I set database pool's queueTimeout 0, the queued connection requests are quickly terminated. The document API says when queueTimeout is 0, the queued connection requests are never terminated.

  3. The input command like this:
    In node-oracledb-5.0.0 root directory, and run node_modules\.bin\mocha test\pool.js, only test use case test/pool.js 2.8.2 generates NJS-040.
    Output:

  1. pool.js
    2.8 connection request queue
    (node:20180) UnhandledPromiseRejectionWarning: AssertionError: expected null to exist
    at F:\ideaworkspace\node-oracledb-5.0.0\test\pool.js:737:28
    at F:\ideaworkspace\node-oracledb-5.0.0\lib\util.js:182:7
    (node:20180) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
    (node:20180) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
  1. Code in here, node-oracledb-5.0.0/test/pool.js, modify the queueTimeout :0:
  describe('2.8 connection request queue', function(){

    function getBlockingSql(secondsToBlock) {
      var blockingSql = '' +
        'declare \n' +
        ' \n' +
        '  l_start timestamp with local time zone := systimestamp; \n' +
        ' \n' +
        'begin \n' +
        ' \n' +
        '  loop \n' +
        '    exit when l_start + interval \'' + (secondsToBlock || 3) + '\' second <= systimestamp; \n' +
        '  end loop; \n' +
        ' \n' +
        'end;';

      return blockingSql;
    }
it('2.8.2 generates NJS-040 if request is queued and queueTimeout expires', function(done) {
      oracledb.createPool(
        {
          user              : dbConfig.user,
          password          : dbConfig.password,
          connectString     : dbConfig.connectString,
          poolMin           : 0,
          poolMax           : 1,
          poolIncrement     : 1,
          poolTimeout       : 1,
          queueTimeout      : 0  //0 seconds
        },
        function(err, pool){
          should.not.exist(err);

          async.parallel(
            [
              function(cb) {
                pool.getConnection(function(err, conn) {
                  should.not.exist(err);

                  conn.execute(getBlockingSql(4), function(err) {
                    should.not.exist(err);
                    conn.release(function(err) {
                      should.not.exist(err);
                      cb();
                    });
                  });
                });
              },
              function(cb) {
                //using setTimeout to help ensure this gets to the db last
                setTimeout(function() {
                  pool.getConnection(function(err, conn) {
                    should.exist(err);
                    (err.message.startsWith("NJS-040:")).should.be.true();

                    should.not.exist(conn);
                    cb();
                  });
                }, 100);
              }
            ],
            function(err){
              should.not.exist(err);
              pool.terminate(function(err) {
                should.not.exist(err);
                done();
              });
            }
          );
        }
      );
    });
  1. My Thought, I see the node-oracledb-5.0.0/lib/pool.js file async function getConnection(a1) method line:117 this._queueTimeout !== 0 is always true, because this._queueTimeout is undefined.
if (this._connectionsOut >= poolMax) {

    // when the queue is huge, throw error early without waiting for queue timeout
    if (this._connRequestQueue.length >= this.queueMax && this.queueMax >= 0) {
      if (this._enableStats) {
        this._totalRequestsRejected += 1;
      }
      throw new Error(nodbUtil.getErrorMessage('NJS-076', this.queueMax));
    }

    // if too many connections are out, wait until room is made available or the
    // queue timeout expires
    await new Promise((resolve, reject) => {

      // set up a payload which will be added to the queue for processing
      const payload = { resolve: resolve, reject: reject };

      // if using a queue timeout, establish the timeout so that when it
      // expires the payload will be removed from the queue and an exception
      // thrown
      if (this._queueTimeout !== 0) {
        payload.timeoutHandle = setTimeout(() => {
          const ix = this._connRequestQueue.indexOf(payload);
          if (ix >= 0) {
            this._connRequestQueue.splice(ix, 1);
          }
          if (this._enableStats) {
            this._totalRequestTimeouts += 1;
            this._totalTimeInQueue += Date.now() - payload.enqueuedTime;
          }
          reject(new Error(nodbUtil.getErrorMessage('NJS-040',
            this.queueTimeout)));
        }, this.queueTimeout);
      }

      // add payload to the queue
      this._connRequestQueue.push(payload);
      if (this._enableStats) {
        payload.enqueuedTime = Date.now();
        this._totalRequestsEnqueued += 1;
        this._maxQueueLength = Math.max(this._maxQueueLength,
          this._connRequestQueue.length);
      }

    });

    // check if pool is draining or closed after delay has completed and throw
    // an appropriate error if so
    this._checkPoolOpen();

  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions