DaReal
DaReal8mo ago

Handling Multiple Mutations In An Action

Hello Support, I am using clerk with my Convex project. When a user signs up, i listen to the event using webhook and insert the user into the database. However, i also need to set some defaults records and fields for the user which will be added. I am planning to use actions to run multiple mutations that inserts the user into the db and also another mutation that sets default values for the field. I am wondering how the error handling works in this case. Assuming the user is added and for some reason the fields are not set, how will i be able to handle such situations efficiently. I am also open to better implementations on how to properly implement this. Thanks in advance.
6 Replies
erquhart
erquhart8mo ago
Welcome! Is it safe to assume it isn't possible to insert the user and set defaults in a single mutation?
DaReal
DaRealOP8mo ago
I can set the defaults for the table which i am creating the mutation for. But i am inserting data into two different tables. or is it possible to chain the insert function? I also notice that when i want to chain another method to the insert method, i only get then, catch, and finally
erquhart
erquhart8mo ago
You can run ctx.db.insert() many times in a single mutation, and all of them will be a part of the same transaction. No need for chaining, you can run each ctx.db method separately within the same mutation.
DaReal
DaRealOP8mo ago
How about if one inserts successfully and the other fails? How do I take care of such? As it may leave partial info stored in the db
erquhart
erquhart8mo ago
mutation() and internalMutation() run as transactions - if an error is thrown at any point, all changes from the entire function are rolled back, they are never committed to the database. Blurb in the docs on this: https://docs.convex.dev/functions/mutation-functions#transactions So if you do:
export const createUser = mutation(async (ctx, args) => {
const userId = await ctx.db.insert('users', { externalId: args.externalId })
await ctx.db.insert('foo', { userId })
throw Error('whoops!')
})
export const createUser = mutation(async (ctx, args) => {
const userId = await ctx.db.insert('users', { externalId: args.externalId })
await ctx.db.insert('foo', { userId })
throw Error('whoops!')
})
the result will only be the thrown error in your logs. Even though both inserts went fine, the thrown error cancels the whole thing. Furthermore, because mutations are ACID transactions, you can trust that any data you're reading during the mutation will not be changed by any other concurrently running mutations during execution.
DaReal
DaRealOP8mo ago
Ohhhh I now have a good understanding Thank you so much. Big kudos to the Convex team. This is the second time i am getting excellent support.

Did you find this page helpful?