Task 1-2: Extract Shared Webhook Failure Helper
Phase: 1 Priority: Medium Module:
marketplaceDepends on: Không có Reference: docs/bountyhunter-blockchain-p2/details/feature-marketplace/SPEC.md
Background
Mỗi @Process() handler trong MarketplaceProcessor đều có đoạn error recovery gần giống nhau: kiểm tra job.attemptsMade === QUEUE_MAX_RETRY - 1, nếu đúng thì gọi postWithRetry(webhook, failurePayload), nếu không thì job.retry(). Pattern này được copy-paste ít nhất 10 lần, làm cho code khó maintain và dễ sai khi cần thay đổi logic retry. Cần extract thành shared helper.
Tasks
Note: Helper nên là method của
MarketplaceProcessor(private) hoặc util function.postWithRetryvàQUEUE_MAX_RETRYphải được inject/import đúng cách trong scope của method.Jobtype import từbull. Kiểm tra type củafailurePayload— thường là object với{ status: 'FAILED', error: string, txHash?: string }.
- [ ] Định nghĩa helper method
notifyWebhookOrRetrytrongMarketplaceProcessor:private async notifyWebhookOrRetry( job: Job, webhookUrl: string, failurePayload: Record<string, unknown>, ): Promise<void> { if (job.attemptsMade >= QUEUE_MAX_RETRY - 1) { this.logger.warn( `[MARKETPLACE] jobId=${job.id} maxRetries=${QUEUE_MAX_RETRY} reached → sending failure webhook` ); await postWithRetry(webhookUrl, failurePayload); } else { this.logger.log( `[MARKETPLACE] jobId=${job.id} attempt=${job.attemptsMade + 1}/${QUEUE_MAX_RETRY} → retrying` ); await job.retry(); } } - [ ] Áp dụng
notifyWebhookOrRetrythay thế đoạn error recovery trong tất cả handler: handleSendAdminSellNfthandleUserBuyNfthandleListingNfthandleCancelListingNfthandleBurnTicket- Và tất cả handler còn lại (kiểm tra đủ 10+)
- [ ] Mỗi handler sau khi refactor có cấu trúc:
@Process(QUEUE_NAME.ADMIN_SELL_NFT) async handleSendAdminSellNft(job: Job): Promise<void> { const { webhookUrl, ...data } = job.data; try { // ... business logic ... await postWithRetry(webhookUrl, successPayload); } catch (error) { this.logger.error(`[MARKETPLACE] action=ADMIN_SELL_NFT jobId=${job.id} error=${error.message}`); await this.notifyWebhookOrRetry(job, webhookUrl, { status: 'FAILED', error: error.message, }); } } - [ ] Verify không còn inline retry/webhook logic trong catch block nào
Verification / Acceptance Criteria
- [ ]
grep -n "job.attemptsMade" src/marketplace/marketplace.processor.tschỉ trả về kết quả trong methodnotifyWebhookOrRetry(không còn inline) - [ ]
grep -n "job.retry()" src/marketplace/marketplace.processor.tschỉ còn trongnotifyWebhookOrRetry - [ ] Tất cả handler đều gọi
notifyWebhookOrRetrytrong catch block - [ ] Khi
attemptsMade < QUEUE_MAX_RETRY - 1→job.retry()được gọi, webhook không được gọi - [ ] Khi
attemptsMade === QUEUE_MAX_RETRY - 1→ webhook failure được gọi,job.retry()không được gọi - [ ] TypeScript compile không có lỗi
Files to Modify
src/marketplace/marketplace.processor.ts