最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Mongoose pass data out of withTransaction helper - Stack Overflow

programmeradmin2浏览0评论

Introduction

Hey there,

I am trying to pass out data from the mongoose withTransaction callback. Right now, I am using the following code which implements callbacks:

const transactionSession = await mongoose.startSession()
await transactionSession.withTransaction(async (tSession) => {
    try {
        // MARK Transaction writes & reads removed for brevity

        console.log("Successfully performed transaction!")
        cb(null, "Any test data")

        return Promise.resolve()
    } catch (error) {
        console.log("Transaction aborted due to error:", error)
        cb(error)

        return Promise.reject()
    }
})

} catch (error) {
    console.log(error)
    return cb(error)
}

A more detailed snippet of the withTransaction helper in use can be found here.

A link to the official Mongoose documentation regarding the withTransaction helper can be found here.

At the moment, I am using a callback to pass out data from the withTransactioncallback:

cb(null, "Any test data")

However, the problem is that naturally the callback is executed first, before the Promise.resolve() is returned. This means, that (in my case) a success response is sent back to the client before any necessary database writes are mitted:

// this is executed first - the callback will send back a response to the client
cb(null, "Any test data")

// only now, after the response already got sent to the client, the transaction is mitted.
return Promise.resolve()

Why I think this is a problem:

Honestly, I am not sure. It just doesn't feel right to send back a success-response to the client, if there hasn't been any database write at that time. Does anybody know the appropriate way to deal with this specific use-case?

I thought about passing data out of the withTransaction helper using something like this:

const transactionResult = await transactionSession.withTransaction({...})

I've tried it, and the response is a CommandResult of MongoDB, which does not include any of the data I included in the resolved promise.

Summary

Is it a problem, if a success response is sent back to the client before the transaction is mitted? If so, what is the appropriate way to pass out data from the withTransaction helper and thereby mitting the transaction before sending back a response?

I would be thankful for any advice I get.

Introduction

Hey there,

I am trying to pass out data from the mongoose withTransaction callback. Right now, I am using the following code which implements callbacks:

const transactionSession = await mongoose.startSession()
await transactionSession.withTransaction(async (tSession) => {
    try {
        // MARK Transaction writes & reads removed for brevity

        console.log("Successfully performed transaction!")
        cb(null, "Any test data")

        return Promise.resolve()
    } catch (error) {
        console.log("Transaction aborted due to error:", error)
        cb(error)

        return Promise.reject()
    }
})

} catch (error) {
    console.log(error)
    return cb(error)
}

A more detailed snippet of the withTransaction helper in use can be found here.

A link to the official Mongoose documentation regarding the withTransaction helper can be found here.

At the moment, I am using a callback to pass out data from the withTransactioncallback:

cb(null, "Any test data")

However, the problem is that naturally the callback is executed first, before the Promise.resolve() is returned. This means, that (in my case) a success response is sent back to the client before any necessary database writes are mitted:

// this is executed first - the callback will send back a response to the client
cb(null, "Any test data")

// only now, after the response already got sent to the client, the transaction is mitted.
return Promise.resolve()

Why I think this is a problem:

Honestly, I am not sure. It just doesn't feel right to send back a success-response to the client, if there hasn't been any database write at that time. Does anybody know the appropriate way to deal with this specific use-case?

I thought about passing data out of the withTransaction helper using something like this:

const transactionResult = await transactionSession.withTransaction({...})

I've tried it, and the response is a CommandResult of MongoDB, which does not include any of the data I included in the resolved promise.

Summary

Is it a problem, if a success response is sent back to the client before the transaction is mitted? If so, what is the appropriate way to pass out data from the withTransaction helper and thereby mitting the transaction before sending back a response?

I would be thankful for any advice I get.

Share Improve this question edited Mar 1, 2020 at 22:41 linus_hologram asked Feb 28, 2020 at 16:48 linus_hologramlinus_hologram 1,71519 silver badges43 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 10 +50

It looks like there is some confusion here as to how to correctly use Promises, on several levels.

Callback and Promise are being used incorrectly

If the function is supposed to accept a callback, don't return a Promise. If the function is supposed to return a Promise, use the callback given by the Promise:

const transactionSession = await mongoose.startSession()
await transactionSession.withTransaction( (tSession) => {
    return new Promise( (resolve, reject) => {
        //using Node-style callback
        doSomethingAsync( (err, testData) => {
            if(err) {
                reject(err);
            } else {
                resolve(testData); //this is the equivalent of cb(null, "Any test data")
            }
        });
    })

Let's look at this in more detail:

return new Promise( (resolve, reject) => { This creates a new Promise, and the Promise is giving you two callbacks to use. resolve is a callback to indicate success. You pass it the object you'd like to return. Note that I've removed the async keyword (more on this later).

For example:

const a = new Promise( (resolve, reject) => resolve(5) );
a.then( (result) => result == 5 ); //true

(err, testData) => { This function is used to map the Node-style cb(err, result) to the Promise's callbacks.

Try/catch are being used incorrectly.

Try/catch can only be used for synchronous statements. Let's pare a synchronous call, a Node-style (i.e. cb(err, result)) asynchronous callback, a Promise, and using await:

  • Synchronous:
try {
    let a = doSomethingSync();
} catch(err) {
    handle(err);
}
  • Async:
doSomethingAsync( (err, result) => {
    if (err) {
        handle(err);
    } else {
        let a = result;
    }
});
  • Promise:
doSomethingPromisified()
    .then( (result) => { 
        let a = result; 
    })
    .catch( (err) => {
        handle(err);
    });
  • Await. Await can be used with any function that returns a Promise, and lets you handle the code as if it were synchronous:
try {
    let a = await doSomethingPromisified();
} catch(err) {
    handle(err);
}

Additional Info

Promise.resolve()

Promise.resolve() creates a new Promise and resolves that Promise with an undefined value. This is shorthand for:

new Promise( (resolve, reject) => resolve(undefined) );

The callback equivalent of this would be:

cb(err, undefined);

async

async goes with await. If you are using await in a function, that function must be declared to be async.

Just as await unwraps a Promise (resolve into a value, and reject into an exception), async wraps code into a Promise. A return value statement gets translated into Promise.resolve(value), and a thrown exception throw e gets translated into Promise.reject(e).

Consider the following code

async () => {
    return doSomethingSync();
}

The code above is equivalent to this:

() => {
    const p = new Promise(resolve, reject);
    try {
        const value = doSomethingSync();
        p.resolve(value);
    } catch(e) {
        p.reject(e);
    }
    return p;
}

If you call either of the above functions without await, you will get back a Promise. If you await either of them, you will be returned a value, or an exception will be thrown.

发布评论

评论列表(0)

  1. 暂无评论