Actualmente me pregunto sobre este problema, tengo un equipo al que quiero agregar un usuario (así que escriba un nuevo usuario en la base de datos para ese equipo) y también quiero aumentar la cantidad de usuarios por los que el equipo debe pagar ( Yo uso suscripciones de banda).
async handleNewUser(user, teamId){ await addUserToTeamInDatabase(user, teamId) await incrementSubscriberQuantityInStripe(teamId) }El problema es, ¿cuál hago primero? Recientemente me encontré con un problema en el que se agregaban usuarios, pero el número de suscriptores no aumentaba. Sin embargo, si los invierto e incremento primero y luego escribo en la base de datos y algo sale mal en esta última parte, el cliente paga más pero no se agrega un nuevo miembro. Una forma posible de abordar esto es con try catch:
handleNewUser(user, teamId) { let userAddedToDatabase = false let userAddedInStripe = false try { await addUserToTeamInDatabase(user, teamId) userAddedToDatabase = true await incrementSubscriberQuantityInStripe(teamId) userAddedToStripe = true } catch (error) { if (userAddedToDatabase && !userAddedInStripe) { await removeUserFromTeamInDatabase() } } }Así que estoy escribiendo el nuevo usuario en la base de datos y luego hago una llamada a la API de stripe. ¿Hay una mejor manera de abordar esto porque se siente torpe? Además, ¿hay un patrón para abordar este problema o un nombre para él?
Estoy usando la base de datos en tiempo real de Firebase.
¡Gracias a todos!
Lo que desea realizar es una transacción. En las bases de datos, una transacción es un grupo de operaciones que tiene éxito si todas sus operaciones tienen éxito. Si al menos una operación falla, no se realizan cambios (todas las demás operaciones se cancelan o revierten).
¡Y Realtime Database admite transacciones! Consulta la documentación
Si ambas operaciones estuvieran en la misma base de datos, normalmente las empaquetaría en una transacción y la base de datos volverá al estado inicial si una de ellas falla. En su caso, tiene operaciones en diferentes sistemas externos (DB y Stripe), por lo que deberá implementar la lógica transaccional usted mismo.
Podría simplificar su ejemplo comprobando de dónde proviene el error en la cláusula catch. Entonces puedes deshacerte de las banderas. Algo como esto:
handleNewUser(user, teamId) { try { await addUserToTeamInDatabase(user, teamId) await incrementSubscriberQuantityInStripe(teamId) } catch (error) { // If we fail to increment subscriber in Stripe, // cancel transaction by removing user from DB if (instanceof error StripeError) { await removeUserFromTeamInDatabase(user, teamId) } // Re-throw error upstream throw error; } }Yo uso una instancia de pero tú cambias la lógica condicional para que se ajuste a tu programa.