返回异步函数中的错误情况如何处理

huangapple go评论62阅读模式
英文:

How to return from async function on error

问题

Here are the translated parts of the code you provided:

 await conn.getconnection().catch((error) => {
    console.log("No connection");
    return;
});
let collection = conn.getdb().collection(type);

Translated:

等待 conn.getconnection().catch((错误) => {
    console.log("无连接");
    返回;
});
let collection = conn.getdb().collection(type);
async function getconnection() {
    client = new MongoClient(url);
    await client.connect();
    db = client.db(dbName);
    console.log("连接到数据库");
}

Translated:

async function getconnection() {
    client = new MongoClient(url);
    await client.connect();
    db = client.db(dbName);
    console.log("连接到数据库");
}

If you have any further questions or need additional translations, please let me know.

英文:
 await conn.getconnection().catch((error)=>{
        console.log("No connection");
        return;
    });
    let collection = conn.getdb().collection(type);
async function getconnection(){
    client = new MongoClient(url);
    await client.connect();
    db = client.db(dbName);
    console.log("Connected to db");
}

The above code is used for connecting the mongodb database. But on not connecting to the database the async function is not going back and the collection is trying to execute causing error. How do i stop execution of function and return to parent function?


Note:-The function works properly when database is running. But when not running the app crashes. I want the error to be caught and not crash.

Error is

No connection
let collection = conn.getdb().collection(type);
                                 ^

TypeError: Cannot read properties of undefined (reading 'collection')

Edit:-

await conn.getconnection().catch(console.error);
    let collection = conn.getdb().collection(type);
    console.log("Entered collection");
    await collection.updateOne(query,{$set : newdata})
        .then(()=>{
            res.send("Done");
        })
        .catch((error)=>{
            console.log(error);
            res.send("Error");
        })
    conn.closedb();

The issue with adding catch altogether is the connection does not get closed if connection is error happens after connection is successfull. So an error happens when the function is called again.

But I can't close connection using finally because if error happens in connect() function then no connection is there to close. So error happens in finally

答案1

得分: 1

First off, this code is a bit messy because you're coding by "side effect". You call something like getConnection() and it apparently has a side effect that it sets a couple of variables in some higher scope (client and db). These are not instance variables of an object. They aren't returned from the function so that caller can use them. They are stuffed into some higher scoped variable. This means that if a second incoming requests calls getconnection() before the first caller has finished using it, then you will overwrite those higher level variables and probably the first values won't get closed or released like they should. This is a separate problem that must be fixed.

Again, as you only show a tiny context of code here, we can't really make larger recommendations on how best to fix this. Probably you should make something like getConnection() just return the connection and not stuff it anywhere and then let the caller use the value they got and release/close it themselves. Then, multiple callers can call getConnection() and nobody will tromp on the other's value. But, there are other designs too where connections are cached/shared or forced to be serialized. You need to fix this also as you likely have concurrency issues the way it is.

Anyway, back to the main question you were asking. Your function for getting the connection here:

async function getconnection(){
    client = new MongoClient(url);
    await client.connect();
    db = client.db(dbName);
    console.log("Connected to db");
}

will reject if client.connect() fails. So, the caller of this function needs to properly handle that rejection. The only place you show calling that function is here where you're logging the error but allowing execution of your code to continue. You need to properly "handle" that error.

try {
    await conn.getconnection();
} catch(e) {
    console.error('error getting database connection', e);
    res.status(500).send('Error connecting to database');
    return;
}
try {
    const collection = conn.getdb().collection(type);
    // may need to sanitize the query variable to make sure it's safe
    await collection.updateOne(query, { $set: newdata });
    res.send("Done");
} catch(e) {
    console.error(e);
    res.status(500).send("Database error");
} finally {
    conn.closedb();
}

This accomplishes the following things:

  1. It handles a rejection from conn.getconnection() directly and separately as you don't want to execute any more code after that error other than sending an error response.
  2. It does not mix await and .then() and .catch(). Pick one style of the other for any given function as flow control gets messy and confusing when you mix them.
  3. It sends an appropriate response to the request in all possible error cases.
  4. It makes sure to call conn.closedb() in all possible error paths where the database connection was retrieved.

NOTE: You don't show where the query variable is coming from, but as it is being fed directly to your .updateOne() method, you MUST make sure it is safe. If it is coming directly out of a form post or query string, then you probably need to sanitize it to make sure it's safe so no possible input can do unintended things to your database.

Flow control with multiple asynchronous operations that wish to have different error handling for different operations is more complicated with .then().catch() than with async/await, but here's one idea how you could do it:

function runIt() {
    return conn.getconnection().catch(e => {
        console.error('error getting database connection', e);
        res.status(500).send('Error connecting to database');
        e.statusSent = true;
        // rethrow the error to skip the following .then() handlers
        throw e;
    }).then(() => {
        const collection = conn.getdb().collection(type);
        // may need to sanitize the query variable to make sure it's safe
        return collection.updateOne(query, { $set: newdata });
    }).then(() => {
        res.send("Done");
    }).catch(e => {
        if (!e.statusSent) {
            console.error(e);
            res.status(500).send("Database error");
        }
        // make sure caller sees the rejection
        throw e;
    }).finally(() => {
        // cleanup database connection
        conn.closedb();
    });
}
英文:

First off, this code is a bit messy because you're coding by "side effect". You call something like getConnection() and it apparently has a side effect that it sets a couple of variables in some higher scope (client and db). These are not instance variables of an object. They aren't returned from the function so that caller can use them. They are stuffed into some higher scoped variable. This means that if a second incoming requests calls getconnection() before the first caller has finished using it, then you will overwrite those higher level variables and probably the first values won't get closed or released like they should. This is a separate problem that must be fixed.

Again, as you only show a tiny a context of code here, we can't really make larger recommendations on how best to fix this. Probably you should make something like getConnection() just return the connection and not stuff it anywhere and then let the caller use the value they got and release/close it themselves. Then, multiple callers can call getConnection() and nobody will tromp on the other's value. But, there are other designs too where connections are cached/shared or forced to be serialized. You need to fix this also as you likely have concurrency issues the way it is.

Anyway, back to the main question you were asking. Your function for getting the connection here:

async function getconnection(){
    client = new MongoClient(url);
    await client.connect();
    db = client.db(dbName);
    console.log("Connected to db");
}

will reject if client.connect() fails. So, the caller of this function needs to properly handle that rejection. The only place you show calling that function is here where you're logging the error, but allowing execution of your code to continue. You need to properly "handle" that error.

await conn.getconnection().catch(console.error);
    let collection = conn.getdb().collection(type);
    console.log("Entered collection");
    await collection.updateOne(query,{$set : newdata})
        .then(()=>{
            res.send("Done");
        })
        .catch((error)=>{
            console.log(error);
            res.send("Error");
        })
    conn.closedb();

I would suggest rewriting that like this:

try {
    await conn.getconnection();
} catch(e) {
    console.error('error getting database connection', e);
    res.status(500).send('Error connecting to database');
    return;
}
try {
    const collection = conn.getdb().collection(type);
    // may need to sanitize the query variable to make sure it's safe
    await collection.updateOne(query, { $set: newdata });
    res.send("Done");
} catch(e) {
    console.error(e);
    res.status(500).send("Database error");
} finally {
    conn.closedb();
}

This accomplishes the following things:

  1. It handles a rejection from conn.getconnection() directly and separately as you don't want to execute any more code after that error other than sending an error response.
  2. It does not mix await and .then() and .catch(). Pick one style of the other for any given function as flow control gets messy and confusing when you mix them.
  3. It sends an appropriate response to the request in all possible error cases.
  4. It makes sure to call conn.closedb() in all possible error paths where the database connection was retrieved.

NOTE: You don't show where the query variable is coming from, but as it is being fed directly to your .updateOne() method, you MUST make sure it is safe. If it is coming directly out of a form post or query string, then you probably need to sanitize it to make sure it's safe so no possible input can do unintended things to your database.


Flow control with multiple asynchronous operations that wish to have different error handling for different operations is more complicated with .then().catch() than with async/await, but here's one idea how you could do it:

function runIt() {
    return conn.getconnection().catch(e => {
        console.error('error getting database connection', e);
        res.status(500).send('Error connecting to database');
        e.statusSent = true;
        // rethrow the error to skip the following .then() handlers
        throw e;
    }).then(() => {
        const collection = conn.getdb().collection(type);
        // may need to sanitize the query variable to make sure it's safe
        return collection.updateOne(query, { $set: newdata });
    }).then(() => {
        res.send("Done");
    }).catch(e => {
        if (!e.statusSent) {
            console.error(e);
            res.status(500).send("Database error");
        }
        // make sure caller sees the rejection
        throw e;
    }).finally(() => {
        // cleanup database connection
        conn.closedb();
    });
}

huangapple
  • 本文由 发表于 2023年5月18日 01:53:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76274936.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定