From 64d22393a658dc9fcf37c93f5dab4f1ac6685fb9 Mon Sep 17 00:00:00 2001 From: mooncitydev Date: Thu, 30 Apr 2026 02:44:06 -0700 Subject: [PATCH] fix: propagate auto-redeem failures instead of swallowing them --- .../src/relayerAutomaticRedeem.service.ts | 60 +++++++++++-------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/backend/apps/relayerAutomaticRedeem/src/relayerAutomaticRedeem.service.ts b/backend/apps/relayerAutomaticRedeem/src/relayerAutomaticRedeem.service.ts index e2782c99..58532e39 100644 --- a/backend/apps/relayerAutomaticRedeem/src/relayerAutomaticRedeem.service.ts +++ b/backend/apps/relayerAutomaticRedeem/src/relayerAutomaticRedeem.service.ts @@ -30,6 +30,7 @@ export class RelayerAutomaticRedeemService { await this.processAutoRedeem(); } catch (error) { this.logger.error('Auto-redeem job failed:', error); + throw error; } finally { this.isRunning = false; } @@ -93,34 +94,29 @@ export class RelayerAutomaticRedeemService { } private async findPendingRedeems(lastReport: any): Promise { - try { - const pendingRedeems = await this.prismaService.redeemRequested.findMany({ - where: { - redeemId: { - notIn: await this.prismaService.redeemClaimed - .findMany({ - select: { redeemId: true }, - }) - .then((claims) => claims.map((c) => c.redeemId)), - }, - epoch: { - lte: lastReport.newHandledEpochLen || 0n, - }, + const pendingRedeems = await this.prismaService.redeemRequested.findMany({ + where: { + redeemId: { + notIn: await this.prismaService.redeemClaimed + .findMany({ + select: { redeemId: true }, + }) + .then((claims) => claims.map((c) => c.redeemId)), }, - orderBy: { redeemId: 'asc' }, - take: BATCH_SIZE_FOR_CLAIM_MULTIPLE_REDEEMS * 5, - }); + epoch: { + lte: lastReport.newHandledEpochLen || 0n, + }, + }, + orderBy: { redeemId: 'asc' }, + take: BATCH_SIZE_FOR_CLAIM_MULTIPLE_REDEEMS * 5, + }); - this.logger.debug('Found pending redeems from database', { - count: pendingRedeems.length, - epochFilter: lastReport.newHandledEpochLen?.toString(), - }); + this.logger.debug('Found pending redeems from database', { + count: pendingRedeems.length, + epochFilter: lastReport.newHandledEpochLen?.toString(), + }); - return pendingRedeems; - } catch (error) { - this.logger.error('Error finding pending redeems:', error); - return []; - } + return pendingRedeems; } private async processPendingRedeemsBatches(pendingRedeems: any[]): Promise { @@ -128,6 +124,8 @@ export class RelayerAutomaticRedeemService { this.logger.info(`Processing ${batches.length} batches of redeems`); + const batchErrors: { batchIndex: number; error: unknown }[] = []; + for (let i = 0; i < batches.length; i++) { const batch = batches[i]; try { @@ -141,8 +139,20 @@ export class RelayerAutomaticRedeemService { } } catch (error) { this.logger.error(`Error processing batch ${i + 1}:`, error); + batchErrors.push({ batchIndex: i + 1, error }); } } + + if (batchErrors.length > 0) { + const nested = batchErrors.map(({ batchIndex, error }) => { + const detail = error instanceof Error ? error.message : String(error); + return new Error(`batch ${batchIndex}/${batches.length}: ${detail}`); + }); + throw new AggregateError( + nested, + `auto-redeem: ${batchErrors.length} of ${batches.length} batch(es) failed` + ); + } } private async processBatch(batch: any[]): Promise {