I am developing cart functionality and for payment processing I am using stripe.
The thing I am concerned is this: I heard that we should avoid long-running transactions to avoid deadlocking whole db? Not sure about this but that's why I want to understand it better.
I am using TypeORM, MySQL, Nest.js for my back-end. For payment processing I am using stripe.
So this means that I will need to perform request (to get payment from the user), but some things could happen. For example it could be insufficient funds, stripe server-side error?
And I am concerned whether this request should be part of transaction? On successful stripe response I have to create records in database and on failure I have to roll-back everything.
There are many things that could go wrong - item which is sold could run out of stock?
This is demo could which shows what actions I want to perform:
@Controller('orders')
@UsePipes(new ValidationPipe({ transform: true }))
@UseInterceptors(ClassSerializerInterceptor)
export class OrdersController {
constructor(
private readonly cartsService: CartsService,
private readonly ordersService: OrdersService,
private readonly ticketsService: TicketsService,
private connection: Connection,
) {}
@Post()
async fullfilOrder(@Body() dto: CreateOrderDto) {
// Get cart for checking the integrity
const cart = await this.cartsService.findByPublicId(dto.cart.publicId);
// Calculate payable amount
const pricePerCompetition = cart.cartItems.map(
item => item.quantity * item.competition.entryPrice,
);
const amount =
pricePerCompetition.length === 0
? 0
: pricePerCompetition.reduce((a, b) => a + b);
// charge user
const stripeCharge = await this.ordersService.submitStripeCharge(
dto.stripeToken,
amount,
cart,
{ firstName: dto.firstName, lastName: dto.lastName, email: dto.email },
);
// create order
const order = await this.ordersService.createOrder(
cart,
dto,
stripeCharge.id,
);
// mark cart status as fulfiled
cart.status = EnumerableCartStatus.FULFILED;
await cart.save();
// create ticket
const ticket = await this.ticketsService.addUserTickets(
AddTicketsDto.fromSuccessfulPayment(
cart.user,
dto.firstName,
dto.lastName,
dto.email,
cart.cartItems,
),
);
//create new cart for user
const newCart = new Cart();
newCart.publicId = v4();
newCart.user = cart.user;
newCart.cartItems = [];
await newCart.save();
delete newCart.user;
return { cart: newCart };
}
}
Any ideas, what approach would I need for this situation? I read about queryRunner: https://docs.nestjs.com/techniques/database but this made me think about stripe request which I am performing, It wouldn't be wise to include it as part of transaction?