fix(c2c): 用updateMany+status条件防止合并时的竞态条件

findFirst找到PENDING订单后,如果被takeOrder接走(状态变MATCHED),
updateMany因status!=PENDING返回count=0,自动回退到创建新订单。

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-01 03:29:27 -08:00
parent 60d99add2c
commit 338321b3a2
1 changed files with 20 additions and 6 deletions

View File

@ -785,7 +785,7 @@ export class C2cService {
const priceDecimal = new Decimal(freshOrder.price);
// 查找是否已有可合并的 PENDING 订单(同 maker + 同类型 + 同价格)
const existingPending = await tx.c2cOrder.findFirst({
let existingPending = await tx.c2cOrder.findFirst({
where: {
makerAccountSequence: freshOrder.makerAccountSequence,
type: freshOrder.type as any,
@ -799,21 +799,35 @@ export class C2cService {
const existingQty = new Decimal(existingPending.quantity.toString());
const mergedQty = existingQty.plus(quantityDecimal);
const mergedTotal = priceDecimal.mul(mergedQty).toString();
restoreOrderNo = existingPending.orderNo;
this.logger.log(
`[EXPIRY][TX] 步骤3: 合并到已有 PENDING 订单 ${existingPending.orderNo}, ` +
`[EXPIRY][TX] 步骤3: 尝试合并到 PENDING 订单 ${existingPending.orderNo}, ` +
`原数量=${existingQty} + 恢复=${quantityDecimal} = ${mergedQty}`,
);
await tx.c2cOrder.update({
where: { orderNo: existingPending.orderNo },
// 用 updateMany + status 条件防止竞态:如果订单在 findFirst 后被 takeOrder 接走count=0
const updateResult = await tx.c2cOrder.updateMany({
where: {
orderNo: existingPending.orderNo,
status: C2C_ORDER_STATUS.PENDING as any,
},
data: {
quantity: mergedQty.toString(),
totalAmount: mergedTotal,
},
});
} else {
if (updateResult.count > 0) {
restoreOrderNo = existingPending.orderNo;
this.logger.log(`[EXPIRY][TX] 步骤3: 合并成功`);
} else {
// 订单已被接走(状态不再是 PENDING回退到创建新订单
this.logger.warn(`[EXPIRY][TX] 步骤3: 订单 ${existingPending.orderNo} 已被接走,改为创建新订单`);
existingPending = null; // fall through to create
}
}
if (shouldRestore && !restoreOrderNo) {
// 无可合并订单,创建新的 PENDING 订单
restoreOrderNo = this.generateOrderNo();
const totalAmount = priceDecimal.mul(quantityDecimal).toString();