When a user signs up, multiple systems need to be provisioned:
If step 3 fails, we shouldn't leave a "zombie" user in Auth0 and Stripe.
A workflow implementing the Saga Pattern to ensure data consistency across microservices.
import { defineWorkflow } from '@dataflows/core'
import { auth0 } from '@dataflows/auth0'
import { stripe } from '@dataflows/stripe'
import { sendgrid } from '@dataflows/sendgrid'
export const onboarding = defineWorkflow({
id: 'customer-onboarding',
trigger: { type: 'webhook', path: '/signup' },
async run({ event, step }) {
const { email, password } = event.body
const compensation = []
try {
// 1. Create Auth0 User
const user = await step.run('create-auth0', async () => {
return auth0.createUser({ email, password })
})
compensation.push(() => auth0.deleteUser(user.id))
// 2. Create Stripe Customer
const customer = await step.run('create-stripe', async () => {
return stripe.customers.create({ email })
})
compensation.push(() => stripe.customers.del(customer.id))
// 3. Send Welcome Email
await step.run('send-email', async () => {
await sendgrid.send({
to: email,
templateId: 'd-welcome-123'
})
})
} catch (error) {
// Rollback on failure
await step.run('rollback', async () => {
for (const undo of compensation.reverse()) {
await undo()
}
})
throw error
}
}
})
Provisions services in parallel to speed up onboarding.
Rolls back changes if any step fails (Saga Pattern).