Skip to content

Conversation

@d4mr
Copy link
Contributor

@d4mr d4mr commented Nov 4, 2025

PR-Codex overview

This PR enhances the logging functionality in the SendWebhookQueue and send-webhook-worker modules. It adds detailed logs for enqueuing webhooks, sending attempts, and responses, including transaction IDs and HMAC information for better traceability and debugging.

Detailed summary

  • Added logger import to send-webhook-queue.ts.
  • Enhanced logging when enqueuing webhooks, including transaction details and webhook count.
  • Introduced logging for webhook sending attempts with transaction ID and HMAC mode.
  • Added warning log if a transaction is not found.
  • Implemented response logging with status and response details, truncating the body.
  • Changed error logging level to "error" for 5xx responses, including additional context.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • Chores
    • Improved webhook delivery reliability with per-webhook idempotency to reduce duplicate deliveries and better retry behavior on server errors
    • Added richer, structured logging and monitoring around webhook enqueueing and delivery (including response outcomes) to aid tracking and support troubleshooting

@coderabbitai
Copy link

coderabbitai bot commented Nov 4, 2025

Walkthrough

Adds structured logging and per-webhook idempotency job IDs when enqueuing transaction webhooks; enriches webhook worker logs with transactionId, hmacMode, response details, and changes 5xx handling to escalate and rethrow to trigger retries.

Changes

Cohort / File(s) Summary
Webhook enqueuing
src/worker/queues/send-webhook-queue.ts
Imports logger. Logs pre-enqueue summary (eventType, queueId, webhook count). Generates a local idempotencyKey per webhook and uses it as the jobId when enqueueing. Logs post-enqueue details (destination URL, webhookId, idempotencyKey, eventType, queueId).
Webhook processing / worker
src/worker/tasks/send-webhook-worker.ts
Extracts transactionId from data.queueId when present. Logs initial webhook attempt (transactionId, destination, eventType, webhookId, hmacMode). On missing transaction for certain event types, logs a warning and returns. Logs responses with status, ok flag, truncated body; selects log level (info/warn/error) by response code. For 5xx responses, escalates log level, includes queueId metadata, and throws to trigger retry.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Producer as Enqueue code
    participant Queue as Job Queue
    participant Worker as Webhook Worker
    Producer->>Producer: compute idempotencyKey per-webhook\nlog pre-enqueue (eventType, queueId, count)
    Producer->>Queue: enqueue job (jobId = idempotencyKey, payload)
    Producer->>Producer: log post-enqueue (destination, webhookId, idempotencyKey)
    Queue->>Worker: deliver job (payload, jobId)
    Worker->>Worker: extract transactionId from data.queueId\nlog attempt (transactionId,destination,eventType,webhookId,hmacMode)
    Worker->>External: send HTTP webhook
    alt success (2xx)
      External-->>Worker: response (status, body)
      Worker->>Worker: log info with responseCode, truncated body
    else client/other non-5xx
      External-->>Worker: response
      Worker->>Worker: log warn with responseCode, truncated body
    else server error (5xx)
      External-->>Worker: response
      Worker->>Worker: log error with responseCode, truncated body, queueId
      Worker->>Worker: throw to trigger retry
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review idempotency key generation and jobId usage in send-webhook-queue.ts to ensure uniqueness and dedup semantics.
  • Verify transactionId extraction from data.queueId in send-webhook-worker.ts handles malformed or absent values safely.
  • Confirm 5xx escalation and thrown errors align with retry/backoff strategy to avoid retry storms.
  • Check consistency of new structured logging fields (service, level, message, queueId, data) and sensitive data exclusion (do not log secrets or HMAC keys).

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is missing required sections from the template: no Linear link, no specific problem statement, no testing steps, and no output/examples. Add Linear issue link, clearly state the problem being solved, provide specific testing steps with expected results, and include output/screenshots demonstrating the changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main change: adding webhook debugging logs to the send-webhook-queue and send-webhook-worker modules.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pb/webhook-debugging-logs

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/worker/queues/send-webhook-queue.ts (1)

165-177: Consider log verbosity for high webhook counts.

While the per-webhook logging is valuable for debugging, it may become verbose if many webhooks are configured for a transaction event. Consider using a debug log level or batching the log output if verbosity becomes an issue in production.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b9a20f8 and 54cd1cc.

📒 Files selected for processing (2)
  • src/worker/queues/send-webhook-queue.ts (2 hunks)
  • src/worker/tasks/send-webhook-worker.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/worker/queues/send-webhook-queue.ts (1)
src/shared/utils/logger.ts (1)
  • logger (89-116)
src/worker/tasks/send-webhook-worker.ts (2)
src/shared/utils/env.ts (1)
  • env (23-188)
src/shared/utils/logger.ts (1)
  • logger (89-116)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: lint
🔇 Additional comments (5)
src/worker/queues/send-webhook-queue.ts (2)

16-16: LGTM!

The logger import is correctly added to support the new debugging logs.


141-163: Good idempotency implementation.

The introduction of an idempotency key based on webhook URL, event type, and queue ID ensures that duplicate webhook deliveries are prevented at the job queue level. Using it as the jobId allows BullMQ to handle deduplication automatically.

src/worker/tasks/send-webhook-worker.ts (3)

31-35: LGTM!

The transactionId extraction is safe and correctly typed as potentially undefined.


85-95: LGTM!

The warning log for missing transactions provides valuable debugging context and is correctly scoped within the transaction event handler.


146-158: LGTM!

The enhanced 5xx error logging with additional context fields and error-level severity is appropriate for debugging retry scenarios.

Comment on lines +37 to +50
// Log webhook attempt with HMAC info
const hmacMode = env.ENABLE_CUSTOM_HMAC_AUTH ? "custom" : "standard";
logger({
service: "worker",
level: "info",
message: `[Webhook] Attempting to send webhook for transaction ${transactionId} at destination ${webhook.url}`,
queueId: transactionId,
data: {
eventType: data.type,
destination: webhook.url,
webhookId: webhook.id,
hmacMode,
},
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Handle undefined transactionId in log messages.

For non-transaction webhook types (e.g., BACKEND_WALLET_BALANCE, WALLET_SUBSCRIPTION), transactionId will be undefined, resulting in log messages like "for transaction undefined". Consider using conditional formatting to improve log clarity.

Apply this diff to improve the log message:

-    message: `[Webhook] Attempting to send webhook for transaction ${transactionId} at destination ${webhook.url}`,
+    message: transactionId 
+      ? `[Webhook] Attempting to send webhook for transaction ${transactionId} at destination ${webhook.url}`
+      : `[Webhook] Attempting to send webhook at destination ${webhook.url}`,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Log webhook attempt with HMAC info
const hmacMode = env.ENABLE_CUSTOM_HMAC_AUTH ? "custom" : "standard";
logger({
service: "worker",
level: "info",
message: `[Webhook] Attempting to send webhook for transaction ${transactionId} at destination ${webhook.url}`,
queueId: transactionId,
data: {
eventType: data.type,
destination: webhook.url,
webhookId: webhook.id,
hmacMode,
},
});
// Log webhook attempt with HMAC info
const hmacMode = env.ENABLE_CUSTOM_HMAC_AUTH ? "custom" : "standard";
logger({
service: "worker",
level: "info",
message: transactionId
? `[Webhook] Attempting to send webhook for transaction ${transactionId} at destination ${webhook.url}`
: `[Webhook] Attempting to send webhook at destination ${webhook.url}`,
queueId: transactionId,
data: {
eventType: data.type,
destination: webhook.url,
webhookId: webhook.id,
hmacMode,
},
});
🤖 Prompt for AI Agents
In src/worker/tasks/send-webhook-worker.ts around lines 37 to 50, the log
includes "for transaction ${transactionId}" but transactionId can be undefined
for non-transaction webhook types; change the log to conditionally include the
transaction id only when present (e.g., "for transaction <id>" or otherwise use
the event type or a generic label like "non-transaction event"), and ensure
queueId/data fields reflect the same (omit queueId or set to a fallback such as
data.type) so logs are clear and don't show "undefined".

Comment on lines +120 to +138
// Log the response
if (resp) {
const logLevel = resp.ok ? "info" : resp.status >= 500 ? "error" : "warn";
logger({
service: "worker",
level: logLevel,
message: `[Webhook] Webhook response received: ${resp.status} for transaction ${transactionId} at destination ${webhook.url}`,
queueId: transactionId,
data: {
eventType: data.type,
destination: webhook.url,
webhookId: webhook.id,
responseCode: resp.status,
responseOk: resp.ok,
hmacMode,
responseBody: resp.body.substring(0, 200), // Truncate response body to first 200 chars
},
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard against non-string response body.

Line 135 calls resp.body.substring(0, 200) without verifying that body is a string. If the webhook response body is an object, null, or undefined, this will throw a runtime error.

Apply this diff to safely handle the response body:

-        responseBody: resp.body.substring(0, 200), // Truncate response body to first 200 chars
+        responseBody: typeof resp.body === 'string' 
+          ? resp.body.substring(0, 200) 
+          : JSON.stringify(resp.body).substring(0, 200), // Truncate response body to first 200 chars
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Log the response
if (resp) {
const logLevel = resp.ok ? "info" : resp.status >= 500 ? "error" : "warn";
logger({
service: "worker",
level: logLevel,
message: `[Webhook] Webhook response received: ${resp.status} for transaction ${transactionId} at destination ${webhook.url}`,
queueId: transactionId,
data: {
eventType: data.type,
destination: webhook.url,
webhookId: webhook.id,
responseCode: resp.status,
responseOk: resp.ok,
hmacMode,
responseBody: resp.body.substring(0, 200), // Truncate response body to first 200 chars
},
});
}
// Log the response
if (resp) {
const logLevel = resp.ok ? "info" : resp.status >= 500 ? "error" : "warn";
logger({
service: "worker",
level: logLevel,
message: `[Webhook] Webhook response received: ${resp.status} for transaction ${transactionId} at destination ${webhook.url}`,
queueId: transactionId,
data: {
eventType: data.type,
destination: webhook.url,
webhookId: webhook.id,
responseCode: resp.status,
responseOk: resp.ok,
hmacMode,
responseBody: typeof resp.body === 'string'
? resp.body.substring(0, 200)
: JSON.stringify(resp.body).substring(0, 200), // Truncate response body to first 200 chars
},
});
}
🤖 Prompt for AI Agents
In src/worker/tasks/send-webhook-worker.ts around lines 120-138, resp.body is
assumed to be a string and resp.body.substring(0, 200) can throw if body is
null/undefined or an object; update the logging to safely handle non-string
bodies by normalizing the body before truncation: if body is a string use it, if
it's an object stringify it (catching possible errors), and if null/undefined
use an empty string, then truncate the normalized string to 200 chars for
responseBody in the logger; ensure this normalization is done inline or via a
small helper and avoid calling substring on non-strings.

logger({
service: "worker",
level: logLevel,
message: `[Webhook] Webhook response received: ${resp.status} for transaction ${transactionId} at destination ${webhook.url}`,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Handle undefined transactionId in log messages.

Similar to the earlier log, this message will show "for transaction undefined" for non-transaction webhooks.

Apply this diff:

-      message: `[Webhook] Webhook response received: ${resp.status} for transaction ${transactionId} at destination ${webhook.url}`,
+      message: transactionId
+        ? `[Webhook] Webhook response received: ${resp.status} for transaction ${transactionId} at destination ${webhook.url}`
+        : `[Webhook] Webhook response received: ${resp.status} at destination ${webhook.url}`,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
message: `[Webhook] Webhook response received: ${resp.status} for transaction ${transactionId} at destination ${webhook.url}`,
message: transactionId
? `[Webhook] Webhook response received: ${resp.status} for transaction ${transactionId} at destination ${webhook.url}`
: `[Webhook] Webhook response received: ${resp.status} at destination ${webhook.url}`,
🤖 Prompt for AI Agents
In src/worker/tasks/send-webhook-worker.ts around line 126, the log message
interpolates transactionId directly and can print "for transaction undefined"
for non-transaction webhooks; change the message construction to conditionally
include the "for transaction <id>" segment only when transactionId is defined
(or use a safe fallback like 'N/A') so logs don't show "undefined" — e.g. build
the message string with a ternary or template fragment that appends `for
transaction ${transactionId}` only when transactionId is truthy.

@d4mr d4mr force-pushed the pb/webhook-debugging-logs branch from 54cd1cc to 3b83955 Compare November 4, 2025 01:24
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/worker/queues/send-webhook-queue.ts (2)

141-150: Good observability enhancement.

The summary log provides a clear high-level view before processing webhooks. The structured data with eventType and webhookCount will be valuable for debugging.

Minor suggestion: The message could be more concise: "Enqueuing transaction webhooks to queue for transaction" → "Enqueuing webhooks for transaction" (the redundancy of "transaction" and "queue" could be reduced).


133-178: Consider adding similar logging to other webhook types.

Transaction webhooks now have comprehensive logging, but the other webhook enqueueing methods (_enqueueContractSubscriptionWebhook, _enqueueBackendWalletBalanceWebhook, _enqueueWalletSubscriptionWebhook) lack similar observability.

For consistent debugging across all webhook types, consider adding similar structured logging to these methods as well. This could be done in a follow-up PR.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 54cd1cc and 3b83955.

📒 Files selected for processing (2)
  • src/worker/queues/send-webhook-queue.ts (2 hunks)
  • src/worker/tasks/send-webhook-worker.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/worker/tasks/send-webhook-worker.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/worker/queues/send-webhook-queue.ts (1)
src/shared/utils/logger.ts (1)
  • logger (89-116)
🔇 Additional comments (3)
src/worker/queues/send-webhook-queue.ts (3)

16-16: LGTM!

The logger import is correctly placed and necessary for the new debugging functionality.


155-163: Good functional improvement: idempotency enforcement.

Extracting the idempotency key to a variable improves readability, and using it as jobId ensures BullMQ will deduplicate jobs automatically. This prevents duplicate webhook deliveries for the same webhook/event/transaction combination.

Note: This is a functional change (enforcing deduplication via BullMQ's job ID mechanism), not just a logging addition. The behavior change is positive and improves reliability.


165-177: Detailed per-webhook tracking added.

The per-webhook log entries provide excellent granularity for debugging webhook delivery issues. The structured data includes all relevant identifiers for tracking individual webhook jobs.

Note: If a transaction triggers many webhooks, this will generate multiple log entries per transaction. This verbosity is appropriate for debugging but can be controlled via the LOG_SERVICES environment variable.

@d4mr d4mr merged commit 191708f into main Nov 4, 2025
7 of 8 checks passed
@d4mr d4mr deleted the pb/webhook-debugging-logs branch November 4, 2025 01:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants