fix(planting-service): improve outbox event confirmation accuracy

- markAsConfirmed now uses aggregateId + eventType for precise matching
- Prevents accidentally confirming multiple events for the same order
- EventAckController passes eventType to markAsConfirmed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2025-12-09 22:16:23 -08:00
parent 8de7a668f0
commit ba5b6141a3
2 changed files with 21 additions and 11 deletions

View File

@ -53,8 +53,11 @@ export class EventAckController {
try { try {
if (message.success) { if (message.success) {
// 标记事件为已确认 // 标记事件为已确认(使用 eventId + eventType 精确匹配)
const confirmed = await this.outboxRepository.markAsConfirmed(message.eventId); const confirmed = await this.outboxRepository.markAsConfirmed(
message.eventId,
message.eventType,
);
if (confirmed) { if (confirmed) {
this.logger.log( this.logger.log(
@ -62,7 +65,7 @@ export class EventAckController {
); );
} else { } else {
this.logger.warn( this.logger.warn(
`[ACK] Event ${message.eventId} not found or already confirmed`, `[ACK] Event ${message.eventId} (${message.eventType}) not found or already confirmed`,
); );
} }
} else { } else {

View File

@ -145,25 +145,32 @@ export class OutboxRepository {
/** /**
* *
* B方案 * B方案
* 使 aggregateId + eventType
*/ */
async markAsConfirmed(eventId: string): Promise<boolean> { async markAsConfirmed(eventId: string, eventType?: string): Promise<boolean> {
// 通过 aggregateId + eventType 查找事件 const whereClause: Prisma.OutboxEventWhereInput = {
aggregateId: eventId,
status: OutboxStatus.SENT,
};
// 如果提供了 eventType则精确匹配
if (eventType) {
whereClause.eventType = eventType;
}
const result = await this.prisma.outboxEvent.updateMany({ const result = await this.prisma.outboxEvent.updateMany({
where: { where: whereClause,
aggregateId: eventId,
status: OutboxStatus.SENT,
},
data: { data: {
status: OutboxStatus.CONFIRMED, status: OutboxStatus.CONFIRMED,
}, },
}); });
if (result.count > 0) { if (result.count > 0) {
this.logger.log(`[OUTBOX] ✓ Event ${eventId} confirmed by consumer`); this.logger.log(`[OUTBOX] ✓ Event ${eventId} (${eventType || 'all types'}) confirmed by consumer`);
return true; return true;
} }
this.logger.warn(`[OUTBOX] Event ${eventId} not found or not in SENT status`); this.logger.warn(`[OUTBOX] Event ${eventId} (${eventType || 'any'}) not found or not in SENT status`);
return false; return false;
} }