简体   繁体   中英

Timeout async/await functions after a few seconds

I created a function to get an Oracle connection using oracledb, but in a few cases, oracledb didn't throw an exception even if he didn't get the connection, apparently he's trying to connect infinitely.

const getConnection = async (): Promise<oracledb.Connection | undefined> => {
  let connection;

  try {
    connection = await oracledb.getConnection({
      user: process.env.DB_LOGIN,
      password: process.env.DB_PASSWORD,
      connectString: process.env.DB_STRING_CONNECTION,
    });
  } catch (err) {
    console.error(err);
  }
  return connection;
};

I saw a few samples using Promise.racing with setTimeout but i couldn't put it in pratice, my tries always get an UnhandledPromiseRejectionWarning on console so i think it isn't the correct way.

Can anybody show me an example how to do that?

It seems you can set a timeout on your connectString :

With Oracle Client 19c, timeouts can be passed in Easy Connect strings, for example to timeout after 15 seconds: "mydbmachine.example.com/orclpdb1?connect_timeout=15"

http://oracle.github.io/node-oracledb/doc/api.html#dbcalltimeouts

Which means you could just as simply construct the string with the timeout:

connectString: process.env.DB_STRING_CONNECTION + '?connect_timeout=15',

Of course there are much better ways to handle the construction of your string.

You can use this connection string format to specify the timeout without 19c client:

(DESCRIPTION=(CONNECT_TIMEOUT=15 ms)(ADDRESS=(PROTOCOL=TCP)(HOST=mymachine.example.com)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)))(RETRY_COUNT=3)

(Also part of the documentation linked)

CertainPerformance's answer is great, however I would suggest not entangling timeout logic with your function. These are generic things and should be implemented separately from your connection logic.

I think the approach below is good because the timeout is configurable by the caller, allowing them to decide how much time a task should wait.

 const sleep = ms => new Promise(r => setTimeout(r, ms)) const timeout = (p, ms) => Promise.race([ p, new Promise((_, r) => sleep(ms).then(_ => r(Error("timeout")))) ]) const fakeConnect = () => sleep(2000).then(_ => "connected:") // Example 1, 500 ms timeout timeout(fakeConnect(). 500).then(console,log. console:error) // Error: timeout // Example 2, 10 second timeout timeout(fakeConnect(). 10000) // connected. ,then(console.log, console.error)

Promise.race should work fine if you implement it properly. Race the getConnection against a Promise that resolves (not rejects), and make sure to chain to a .catch .

const getConnection = (): Promise<oracledb.Connection | undefined> => {
    return Promise.race([
        oracledb.getConnection({
            user: process.env.DB_LOGIN,
            password: process.env.DB_PASSWORD,
            connectString: process.env.DB_STRING_CONNECTION,
        }),
        new Promise((resolve) => { setTimeout(resolve, 5000); })
    ])
        .catch((error) => {
            // this will only be entered into if getConnection rejects (and not if it times out)
            console.log(error);
        })
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM