feat: 增强下游重投与签名质量检测

This commit is contained in:
hectorzhao
2026-08-12 17:05:53 +08:00
parent 1d8d6701a6
commit 4994841709
23 changed files with 960 additions and 67 deletions
+36
View File
@@ -19,6 +19,7 @@ import { aggregateReceiptSegmentState, isSameUpstreamEndpointIdentity, receiptEv
import type { DownstreamDeliveryQueueRequest } from './downstream-receipt-targets';
import { SendSubmissionService, type SendResourceValidationOptions } from './send-submission.service';
import { SendCompletionService, type SendCompletionFacade } from './send-completion.service';
import { SendDownstreamRequeueTaskService, type DownstreamRequeueFilter } from './send-downstream-requeue-task.service';
@Injectable()
export class SendChainService implements OnModuleInit, OnModuleDestroy {
@@ -37,8 +38,10 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
private inboundLongMessageIntervalTimer?: ReturnType<typeof setInterval>;
private upstreamReceiptInboxInitialTimer?: ReturnType<typeof setTimeout>;
private upstreamReceiptInboxIntervalTimer?: ReturnType<typeof setInterval>;
private downstreamRequeueTaskIntervalTimer?: ReturnType<typeof setInterval>;
private readonly submission: SendSubmissionService;
private readonly completion: SendCompletionService;
private readonly downstreamRequeueTasks: SendDownstreamRequeueTaskService;
constructor(
private readonly prisma: PrismaService,
@@ -68,6 +71,7 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
openApi,
this as unknown as SendCompletionFacade,
);
this.downstreamRequeueTasks = new SendDownstreamRequeueTaskService(prisma, this);
}
onModuleInit() {
@@ -129,6 +133,13 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
);
this.upstreamReceiptInboxIntervalTimer.unref?.();
}
if (process.env.CMPP_DOWNSTREAM_REQUEUE_TASK_SCAN_ENABLED !== 'false') {
this.downstreamRequeueTaskIntervalTimer = setInterval(
() => void this.downstreamRequeueTasks.runScan().catch((error) => this.logger.error(`Downstream requeue task scan failed: ${String(error)}`)),
positiveInteger(process.env.CMPP_DOWNSTREAM_REQUEUE_TASK_SCAN_INTERVAL_MS, 1_000),
);
this.downstreamRequeueTaskIntervalTimer.unref?.();
}
}
async onModuleDestroy() {
@@ -140,6 +151,7 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
if (this.inboundLongMessageIntervalTimer) clearInterval(this.inboundLongMessageIntervalTimer);
if (this.upstreamReceiptInboxInitialTimer) clearTimeout(this.upstreamReceiptInboxInitialTimer);
if (this.upstreamReceiptInboxIntervalTimer) clearInterval(this.upstreamReceiptInboxIntervalTimer);
if (this.downstreamRequeueTaskIntervalTimer) clearInterval(this.downstreamRequeueTaskIntervalTimer);
await this.worker?.close();
await this.sendQueue?.close();
await this.gatewayQueue?.close();
@@ -481,6 +493,10 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
return this.completion.requeueGatewaySubmitDeadLetter(id, data);
}
async resolveGatewaySubmitDeadLetter(id: string, operatorId?: string) {
return this.completion.resolveGatewaySubmitDeadLetter(id, operatorId);
}
async recoverStaleGatewaySubmitRequeues(now = new Date()) {
return this.completion.recoverStaleGatewaySubmitRequeues(now);
}
@@ -497,6 +513,26 @@ export class SendChainService implements OnModuleInit, OnModuleDestroy {
return this.completion.batchRequeueDownstreamDeliveries(ids);
}
previewDownstreamRequeueTask(filter: DownstreamRequeueFilter) {
return this.downstreamRequeueTasks.preview(filter);
}
createDownstreamRequeueTask(data: { filter: DownstreamRequeueFilter; snapshotAt: string; reason: string; ratePerSecond?: number; consecutiveFailureLimit?: number }, operatorId?: string) {
return this.downstreamRequeueTasks.create(data, operatorId);
}
listDownstreamRequeueTasks(query: { status?: string; page?: number; pageSize?: number }) {
return this.downstreamRequeueTasks.list(query);
}
getDownstreamRequeueTask(id: string) {
return this.downstreamRequeueTasks.get(id);
}
changeDownstreamRequeueTaskStatus(id: string, action: 'pause' | 'resume' | 'terminate', operatorId?: string) {
return this.downstreamRequeueTasks.changeStatus(id, action, operatorId);
}
async claimUplinkMatchCandidate(uplinkMessageId: string, candidateId: string, operatorId?: string) {
return this.completion.claimUplinkMatchCandidate(uplinkMessageId, candidateId, operatorId);
}