Announcing Transactional Actions in Gadget
Transactions are units of work that you want the database to treat as an indivisible whole: either all of the database changes take place, or none of them. Gadget now offers built-in transaction support, as well as the ability to toggle transactions on and off, as needed.
Overview
It’s not uncommon to write code that touches multiple pieces of data at once. Real world processes often tend to need this: when you purchase from an online store, the order is created at the same time as inventory being deducted. You don’t want to deduct the inventory if the order doesn’t go through (e.g. payment failure). To support this, backends typically use database transactions that wrap a set of changes and commit them to the database at the same time.
Starting today, all Gadget Actions come with built-in transactionality that can be toggled on and off. Gadget’s database transactions wrap the entire effect stack so that either all or none of your changes commit together. This includes any database changes made by your JavaScript code files.
When two or more actions are invoked together in a single API call, Gadget wraps them in a database transaction which guarantees they’ll be atomic. For example, if we were to make an API call to create a blog post record and related image records (stored in a separate, related model), we would use Gadget’s nested actions as follows:
If either of our blog post images fail to save, say because a validation deemed the image to be too big, then the whole transaction will abort and neither the blog post nor the image records will be saved. This saves you from having to write any clean up code, because your database never commits the changes unless all of the changes are successful.
In the Gadget framework, the <inline-code>Run<inline-code>, <inline-code>Success<inline-code>, and <inline-code>Failure<inline-code> effect stacks each come with their own transaction boundary. By default, <inline-code>Run Effects<inline-code> are transactional, whereas <inline-code>Success<inline-code> and <inline-code>Failure Effects<inline-code> are not. You can change the transactionality of any effect stack in Gadget by toggling the transaction icon.
Gadget transactions have a 5 second timeout, in order to preserve scalability. This should be long enough for most <inline-code>Actions<inline-code>, but if you’re working with external APIs or high volumes of data, it can be convenient to turn off this transaction to avoid the timeout, and instead manage transactions yourself with the explicit <inline-code>api.transaction<inline-code> wrapper.