1) When I call order.Save() is there a implicit sql transaction which wraps all the sql delete/insert/update statements that I assume are executed under the hood? Or is it my responsibility to do transaction management?
2) Related, what happens if two requests try to save the same order at the same time (or even a save and read concurrent requests)? Is that handled by TeaCommerece/Umbraco/PetaPOCO, or is it my responsibility? I'm trying to understand the reason for a an duplicate key sql exception being thrown in my code on a webhook call from the payment provider (Stripe).
1) As of 3.3.1 yes. An order save is now performed within a transaction (this was added for the exact reason you are experiencing)
2) This is an area that needs to be looked into further. The transaction added in 3.3.1 does resolve that key error, however it doesn't resolve the issue entirely. The main issue being, the two requests still run, which can allow logic to be run twice that you'd expect to only run once. ie, should the order be finalized as part of the first request, it is possible for the second request to cause a save which runs finalization logic again (because the internal model hasn't been updated yet and so it doesn't know it's being finalized already). This can result in the order being finalized twice and thus firing events for things like sending out emails twice.
I'm not quite sure how to resolve that one yet, but the transaction added in 3.3.1 is a step in the right direction.
If you have an ideas of something you were planning to implement, do let me know as it could help the route I go.
Could you elaborate a bit on what you mean by "... because the internal model hasn't been updated yet ..."?
Is this because the Order object is being cached? It's the caching I'm curious about here, and my curiosity might be unrelated to your reply above. Anyway, there's a CacheService in TeaCommerce, how is that used?
Let's say I wrap some code (e.g. in my own custom provider) inside an SQL transaction. I read an order object using TeaCommerceHelper.GetOrder(storeId, orderId) and then make some changes to the order. Now, let's say the transaction fails for some reason (or is intentionally rolled back). I let go of the order object instance, but a bit later (same request) I re-read the order again. Will the new order object have the "dirty" changes from the prior transaction, or am I guaranteed an order object with fresh data?
I'm still on 3.2.4, working my way through things in preparation of upgrades to TeaCommerce and Stripe...
Yea, based on your example, the order would retain the changes that occurred even though the transaction failed, however those changes won't have been persisted.
The order is stored in memory cache (yes this is what the caching service is used for, caching all TC based entities) so any changes to the instance will be remembered by the cache until the cache is cleared and the entity is reloaded from the DB. To make it truly transitional we'd either need the models to support transactions, or we clone the order before making any changes and push it back to the cache if successful or we say if a transaction fails then just remove the order from the cache so that the next time it's requested, it's re-fetched from the DB.
We are a bit behind on the version right now (3.2.4), and have a custom Stripe implementation. I'll probably take the time to upgrade and synchronize with 3.3.1 in the next couple weeks. There's a chance I might be able to give you some feedback then :-)
Database Transactions and concurrent requests
Hi,
1) When I call order.Save() is there a implicit sql transaction which wraps all the sql delete/insert/update statements that I assume are executed under the hood? Or is it my responsibility to do transaction management?
2) Related, what happens if two requests try to save the same order at the same time (or even a save and read concurrent requests)? Is that handled by TeaCommerece/Umbraco/PetaPOCO, or is it my responsibility? I'm trying to understand the reason for a an duplicate key sql exception being thrown in my code on a webhook call from the payment provider (Stripe).
Thanks, -Tor
Hi Tor,
1) As of 3.3.1 yes. An order save is now performed within a transaction (this was added for the exact reason you are experiencing)
2) This is an area that needs to be looked into further. The transaction added in 3.3.1 does resolve that key error, however it doesn't resolve the issue entirely. The main issue being, the two requests still run, which can allow logic to be run twice that you'd expect to only run once. ie, should the order be finalized as part of the first request, it is possible for the second request to cause a save which runs finalization logic again (because the internal model hasn't been updated yet and so it doesn't know it's being finalized already). This can result in the order being finalized twice and thus firing events for things like sending out emails twice.
I'm not quite sure how to resolve that one yet, but the transaction added in 3.3.1 is a step in the right direction.
If you have an ideas of something you were planning to implement, do let me know as it could help the route I go.
Hope this helps
Matt
Could you elaborate a bit on what you mean by "... because the internal model hasn't been updated yet ..."?
Is this because the Order object is being cached? It's the caching I'm curious about here, and my curiosity might be unrelated to your reply above. Anyway, there's a CacheService in TeaCommerce, how is that used?
Let's say I wrap some code (e.g. in my own custom provider) inside an SQL transaction. I read an order object using TeaCommerceHelper.GetOrder(storeId, orderId) and then make some changes to the order. Now, let's say the transaction fails for some reason (or is intentionally rolled back). I let go of the order object instance, but a bit later (same request) I re-read the order again. Will the new order object have the "dirty" changes from the prior transaction, or am I guaranteed an order object with fresh data?
I'm still on 3.2.4, working my way through things in preparation of upgrades to TeaCommerce and Stripe...
-Tor
Hi Tor,
Yea, based on your example, the order would retain the changes that occurred even though the transaction failed, however those changes won't have been persisted.
The order is stored in memory cache (yes this is what the caching service is used for, caching all TC based entities) so any changes to the instance will be remembered by the cache until the cache is cleared and the entity is reloaded from the DB. To make it truly transitional we'd either need the models to support transactions, or we clone the order before making any changes and push it back to the cache if successful or we say if a transaction fails then just remove the order from the cache so that the next time it's requested, it's re-fetched from the DB.
Hope this helps
Matt
Ok, thanks Matt!
We are a bit behind on the version right now (3.2.4), and have a custom Stripe implementation. I'll probably take the time to upgrade and synchronize with 3.3.1 in the next couple weeks. There's a chance I might be able to give you some feedback then :-)
-Tor
Hehe, thanks Tor.
I'm always open to feedback 👍
All the best
Matt
is working on a reply...