feat(c2c): 添加expireOrder事务流程的详细调试日志
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
627c3c943c
commit
49ba2fcb19
|
|
@ -682,7 +682,15 @@ export class C2cService {
|
|||
async processExpiredOrders(): Promise<number> {
|
||||
// 计算 PENDING 订单的过期截止时间
|
||||
const pendingCutoff = new Date(Date.now() - DEFAULT_PENDING_TIMEOUT_HOURS * 60 * 60 * 1000);
|
||||
this.logger.debug(`[EXPIRY] 开始扫描超时订单, PENDING截止时间: ${pendingCutoff.toISOString()}`);
|
||||
|
||||
const expiredOrders = await this.c2cOrderRepository.findExpiredOrders(pendingCutoff);
|
||||
|
||||
if (expiredOrders.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
this.logger.log(`[EXPIRY] 发现 ${expiredOrders.length} 个超时订单: ${expiredOrders.map(o => `${o.orderNo}(${o.type}/${o.status})`).join(', ')}`);
|
||||
let processedCount = 0;
|
||||
|
||||
for (const order of expiredOrders) {
|
||||
|
|
@ -690,14 +698,11 @@ export class C2cService {
|
|||
await this.expireOrder(order);
|
||||
processedCount++;
|
||||
} catch (error) {
|
||||
this.logger.error(`处理超时订单失败: ${order.orderNo}`, error);
|
||||
this.logger.error(`[EXPIRY] 处理超时订单失败: ${order.orderNo}`, error);
|
||||
}
|
||||
}
|
||||
|
||||
if (processedCount > 0) {
|
||||
this.logger.log(`处理了 ${processedCount} 个超时订单`);
|
||||
}
|
||||
|
||||
this.logger.log(`[EXPIRY] 本轮处理完成: 成功 ${processedCount}/${expiredOrders.length}`);
|
||||
return processedCount;
|
||||
}
|
||||
|
||||
|
|
@ -709,17 +714,23 @@ export class C2cService {
|
|||
const lockKey = `c2c:expire:${order.orderNo}`;
|
||||
const lockValue = await this.redis.acquireLock(lockKey, 30);
|
||||
if (!lockValue) {
|
||||
return; // 其他进程正在处理
|
||||
this.logger.debug(`[EXPIRY] 订单 ${order.orderNo} 正被其他进程处理,跳过`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 重新获取订单,确保状态一致
|
||||
const freshOrder = await this.c2cOrderRepository.findByOrderNo(order.orderNo);
|
||||
if (!freshOrder || (
|
||||
if (!freshOrder) {
|
||||
this.logger.warn(`[EXPIRY] 订单 ${order.orderNo} 不存在,跳过`);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
freshOrder.status !== C2C_ORDER_STATUS.PENDING &&
|
||||
freshOrder.status !== C2C_ORDER_STATUS.MATCHED &&
|
||||
freshOrder.status !== C2C_ORDER_STATUS.PAID
|
||||
)) {
|
||||
) {
|
||||
this.logger.debug(`[EXPIRY] 订单 ${order.orderNo} 状态已变为 ${freshOrder.status},无需处理`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -728,27 +739,39 @@ export class C2cService {
|
|||
const isSell = freshOrder.type === C2C_ORDER_TYPE.SELL;
|
||||
let restoreOrderNo: string | null = null;
|
||||
|
||||
this.logger.log(
|
||||
`[EXPIRY] 开始处理订单 ${freshOrder.orderNo}: ` +
|
||||
`类型=${freshOrder.type}, 状态=${freshOrder.status}, ` +
|
||||
`数量=${freshOrder.quantity}, 价格=${freshOrder.price}, ` +
|
||||
`maker=${freshOrder.makerAccountSequence}, taker=${freshOrder.takerAccountSequence || '无'}, ` +
|
||||
`需恢复=${shouldRestore}`,
|
||||
);
|
||||
|
||||
await this.prisma.$transaction(async (tx) => {
|
||||
// 1. 解冻卖方的积分值(如果需要)
|
||||
if (freshOrder.status === C2C_ORDER_STATUS.PENDING) {
|
||||
// PENDING SELL:解冻 maker
|
||||
if (isSell) {
|
||||
this.logger.log(`[EXPIRY][TX] 步骤1: 解冻 PENDING SELL maker ${freshOrder.makerAccountSequence} 的 frozenCash -= ${quantityDecimal}`);
|
||||
await tx.tradingAccount.update({
|
||||
where: { accountSequence: freshOrder.makerAccountSequence },
|
||||
data: { frozenCash: { decrement: quantityDecimal.toNumber() } },
|
||||
});
|
||||
} else {
|
||||
this.logger.debug(`[EXPIRY][TX] 步骤1: PENDING BUY 无冻结资产,跳过解冻`);
|
||||
}
|
||||
// PENDING BUY:无冻结
|
||||
} else if (!isSell && freshOrder.takerAccountSequence) {
|
||||
// MATCHED/PAID BUY:解冻 taker(卖方)
|
||||
this.logger.log(`[EXPIRY][TX] 步骤1: 解冻 ${freshOrder.status} BUY taker ${freshOrder.takerAccountSequence} 的 frozenCash -= ${quantityDecimal}`);
|
||||
await tx.tradingAccount.update({
|
||||
where: { accountSequence: freshOrder.takerAccountSequence },
|
||||
data: { frozenCash: { decrement: quantityDecimal.toNumber() } },
|
||||
});
|
||||
} else if (isSell && shouldRestore) {
|
||||
this.logger.log(`[EXPIRY][TX] 步骤1: ${freshOrder.status} SELL 保持冻结不变,冻结量将转给恢复的 PENDING 订单`);
|
||||
}
|
||||
// MATCHED/PAID SELL + shouldRestore:不解冻,冻结直接转给新 PENDING 订单
|
||||
|
||||
// 2. 标记订单为过期
|
||||
this.logger.log(`[EXPIRY][TX] 步骤2: 标记订单 ${freshOrder.orderNo} 状态 ${freshOrder.status} -> EXPIRED`);
|
||||
await tx.c2cOrder.update({
|
||||
where: { orderNo: freshOrder.orderNo },
|
||||
data: {
|
||||
|
|
@ -761,6 +784,12 @@ export class C2cService {
|
|||
if (shouldRestore) {
|
||||
const priceDecimal = new Decimal(freshOrder.price);
|
||||
restoreOrderNo = this.generateOrderNo();
|
||||
const totalAmount = priceDecimal.mul(quantityDecimal).toString();
|
||||
this.logger.log(
|
||||
`[EXPIRY][TX] 步骤3: 恢复为新 PENDING 订单 ${restoreOrderNo}, ` +
|
||||
`类型=${freshOrder.type}, maker=${freshOrder.makerAccountSequence}, ` +
|
||||
`数量=${quantityDecimal}, 总金额=${totalAmount}`,
|
||||
);
|
||||
await tx.c2cOrder.create({
|
||||
data: {
|
||||
orderNo: restoreOrderNo,
|
||||
|
|
@ -772,7 +801,7 @@ export class C2cService {
|
|||
makerNickname: freshOrder.makerNickname,
|
||||
price: freshOrder.price,
|
||||
quantity: quantityDecimal.toString(),
|
||||
totalAmount: priceDecimal.mul(quantityDecimal).toString(),
|
||||
totalAmount,
|
||||
minAmount: '0',
|
||||
maxAmount: '0',
|
||||
paymentMethod: isSell ? freshOrder.paymentMethod : null,
|
||||
|
|
@ -783,17 +812,24 @@ export class C2cService {
|
|||
remark: freshOrder.remark,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.logger.debug(`[EXPIRY][TX] 步骤3: PENDING 订单无需恢复`);
|
||||
}
|
||||
});
|
||||
|
||||
// 事务成功后记日志
|
||||
this.logger.log(`C2C订单已过期: ${freshOrder.orderNo}, 原状态: ${freshOrder.status}`);
|
||||
if (restoreOrderNo) {
|
||||
this.logger.log(`过期恢复: 订单 ${freshOrder.orderNo} 已恢复为新 PENDING 订单 ${restoreOrderNo}, 数量: ${quantityDecimal}`);
|
||||
}
|
||||
this.logger.log(
|
||||
`[EXPIRY] 事务提交成功: 订单 ${freshOrder.orderNo} (${freshOrder.type}/${freshOrder.status}) -> EXPIRED` +
|
||||
(restoreOrderNo ? `, 恢复为 ${restoreOrderNo} (PENDING, 数量=${quantityDecimal})` : ''),
|
||||
);
|
||||
} catch (error: any) {
|
||||
// 事务失败 = 全部回滚,不会出现不一致状态
|
||||
this.logger.error(`expireOrder 事务失败: ${order.orderNo}: ${error.message}`);
|
||||
this.logger.error(
|
||||
`[EXPIRY] 事务失败,已回滚: 订单=${order.orderNo}, ` +
|
||||
`错误=${error.message}`,
|
||||
error.stack,
|
||||
);
|
||||
throw error;
|
||||
} finally {
|
||||
await this.redis.releaseLock(lockKey, lockValue);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue