Mongo may retry running it (calling the function again) if a "TransaientTransactionError" is raised (the transaction is retried from the client side rather than at the cluster).
However, when the driver calls your function again it doesn't invalidate the `session` object - so previous calls to the same function can make updates to the database.
Let's say `someOp` does something that causes the transaction to retry and `someOtherOp` is doing something non-mongo-related in the meantime (like pulling a value from redis). Now `someOtherOp` reached the mongo part of its code and it is executing it happily with the same session object (so operations succeed although they really shouldn't)
The point of transactions like you said is to perform multiple operations atomically and for them to happen "exactly once or not at all". With Mongo in practice it is very easy to get "Once and some leftovers from a previous attempt".
Sorry, I haven’t had my coffee yet. If I am reading this correctly, either someOp() or someOtherOp() may execute first, no? And if you introduce an external database, why do you expect Mongo to handle that rollback? Say someOtherOp() increments a Redis value by 1. If that part executed first since both are asynchronous here, what would a Mongo session have to do with it?
What exactly would invalidating that session object do here? And what would the session object do after it was invalidated?
Thanks for this explanation. So if I understand correctly, `someOp` has thrown an error but this doesn't affect `someOtherOp`? So `someOtherOp` will end up being called twice?
I think this is the expected behaviour of the transaction but the problem comes from the fact you wrap all DB operation inside a Promise.all.
Because you wrap the DB operations inside a Promise.all, it means it will run them all BUT it will not revert them if one fails (it's not atomic, it just says that one has failed and you need to catch it), it will reject them but not revert them. (the CUD operation will already have changed the data)
The problem I believe is the transaction is considering the Promise.all and not what's inside of it so it will run it again despite the fact that some have already succeeded earlier
I think you just have to resolve each of them outside a Promise.all.
In your case because Promise.all has been rejected it will redo the transaction, therefor it will redo the one that have already worked in the first call.
Not op, I think what he means is the session, even when already failed once, can still be used (without error) in the next operation without being invalidated.
Without promise.all, I think it can be replicated like this:
I have found people to attack me when I make a technical criticism of technologies they like.
Am I expected to justify being able to code in HN? I could go on about being a maintainer of the two most promise libraries in npm (bluebird and Q), being node core, organizing promises sessions for APIs in Node core and having over 1000 answers about promises in SO.
I generally find that sort of "non-technical chat" boring compared to the technical stuff and appeal to authority kind of lame.
The only other person attacked in this issue is
aphyr, so I believe I am in very good company in this particular instance.
However, when the driver calls your function again it doesn't invalidate the `session` object - so previous calls to the same function can make updates to the database.
Let's say `someOp` does something that causes the transaction to retry and `someOtherOp` is doing something non-mongo-related in the meantime (like pulling a value from redis). Now `someOtherOp` reached the mongo part of its code and it is executing it happily with the same session object (so operations succeed although they really shouldn't)
The point of transactions like you said is to perform multiple operations atomically and for them to happen "exactly once or not at all". With Mongo in practice it is very easy to get "Once and some leftovers from a previous attempt".