Skip to content

Improve timeout handling and error recovery#667

Merged
grunch merged 2 commits into
mainfrom
fix/timeout-handling-improvements
Jun 26, 2025
Merged

Improve timeout handling and error recovery#667
grunch merged 2 commits into
mainfrom
fix/timeout-handling-improvements

Conversation

@grunch

@grunch grunch commented Jun 26, 2025

Copy link
Copy Markdown
Member
  • Enhanced Lightning Network error handling with specific timeout detection
  • Made pathfinding and bot handler timeouts configurable via environment variables
  • Implemented exponential backoff retry strategy for failed payments
  • Added timeout monitoring and structured logging for better debugging
  • Enhanced PendingPayment model with error tracking and retry scheduling

Fixes 60-second timeout issues that were causing bot unresponsiveness.

Summary by CodeRabbit

  • New Features

    • Added configurable timeout settings for Lightning Network pathfinding and Telegram bot handler.
    • Introduced exponential backoff and retry scheduling for pending payments.
    • Enhanced error tracking and retry metadata for failed payments.
    • Added detailed operation duration and timeout logging utilities.
    • Included new documentation outlining project overview, development, and architecture.
  • Bug Fixes

    • Improved error handling and logging for payment failures, including specific error types and structured logs.
  • Chores

    • Updated environment variable samples to reflect new configuration options.

- Enhanced Lightning Network error handling with specific timeout detection
- Made pathfinding and bot handler timeouts configurable via environment variables
- Implemented exponential backoff retry strategy for failed payments
- Added timeout monitoring and structured logging for better debugging
- Enhanced PendingPayment model with error tracking and retry scheduling

Fixes 60-second timeout issues that were causing bot unresponsiveness.
@coderabbitai

coderabbitai Bot commented Jun 26, 2025

Copy link
Copy Markdown
Contributor
## Walkthrough

Timeouts for Lightning Network pathfinding and Telegram bot handling are now configurable via environment variables. The payment retry logic introduces exponential backoff with scheduled retries and enhanced error tracking. Logging utilities for operation duration and timeouts are added. The pending payment model is extended to store error and retry metadata. A new CLAUDE.md documentation file was added describing the project, architecture, and development setup.

## Changes

| File(s)                                      | Change Summary                                                                                  |
|----------------------------------------------|------------------------------------------------------------------------------------------------|
| `.env-sample`                                | Added `LN_PATHFINDING_TIMEOUT` and `BOT_HANDLER_TIMEOUT` environment variables.                 |
| `app.ts`                                     | Made Telegram bot handler timeout configurable via `BOT_HANDLER_TIMEOUT` environment variable.  |
| `jobs/pending_payments.ts`                   | Added exponential backoff for retries, improved error handling, and updated retry conditions.  |
| `ln/pay_request.ts`                          | Introduced configurable pathfinding timeout, detailed error handling, and enhanced logging.    |
| `logger.ts`                                  | Added `logTimeout` and `logOperationDuration` utility functions for structured logging.        |
| `models/pending_payment.ts`                  | Extended model with `last_error` and `next_retry` fields for error and retry tracking.         |
| `CLAUDE.md`                                  | Added new documentation explaining project overview, architecture, and development setup.      |

## Poem

> In the warren, timeouts now obey,  
> Configurable, they hop and sway.  
> With errors tracked and retries wise,  
> The payments wait, then re-arise.  
> Logs now sing of time elapsed,  
> As bunnies code, no detail lapsed.  
> 🐇✨ System hops ahead—no surprise!  

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-26T19_03_38_623Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment
  • Commit Unit Tests in branch fix/timeout-handling-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🔭 Outside diff range comments (1)
app.ts (1)

28-38: Critical: Fix options object overwriting bug.

The handlerTimeout configuration is lost when SOCKS_PROXY_HOST is set because the options object is completely overwritten. The proxy configuration should be merged with the existing options.

-      let options: Partial<Telegraf.Options<CommunityContext>> = { handlerTimeout };
+      let options: Partial<Telegraf.Options<CommunityContext>> = { handlerTimeout };
       if (process.env.SOCKS_PROXY_HOST) {
         const agent = new SocksProxyAgent(process.env.SOCKS_PROXY_HOST);
-        options = {
+        options = {
+          ...options,
           telegram: {
             agent,
           },
         };
       }
♻️ Duplicate comments (1)
jobs/pending_payments.ts (1)

159-164: Duplicate exponential backoff logic.

This is identical to the logic in the first function. Consider extracting to a shared utility function as suggested above.

🧹 Nitpick comments (6)
models/pending_payment.ts (1)

42-43: Consider the default value calculation for next_retry.

The arrow function for next_retry default works correctly, but consider if this calculation should be consistent with the retry logic elsewhere in the codebase.

logger.ts (1)

37-51: Consider input validation for startTime parameter.

The logOperationDuration function is well-implemented with appropriate logging levels and structured data. Consider adding validation to ensure startTime is a valid timestamp to prevent negative durations.

 export const logOperationDuration = (operation: string, startTime: number, success: boolean = true) => {
+  if (startTime <= 0 || startTime > Date.now()) {
+    logger.warn(`Invalid startTime provided for operation ${operation}: ${startTime}`);
+    return;
+  }
   const duration = Date.now() - startTime;
jobs/pending_payments.ts (2)

25-30: Consider extracting exponential backoff logic to a utility function.

The exponential backoff calculation is well-implemented with reasonable base delay (5 minutes) and maximum delay (1 hour). However, this logic is duplicated in both functions.

+// Utility function for exponential backoff calculation
+const calculateNextRetryDelay = (attempts: number): number => {
+  const baseDelay = 5 * 60 * 1000; // 5 minutes
+  const exponentialDelay = baseDelay * Math.pow(2, attempts - 1);
+  const maxDelay = 60 * 60 * 1000; // 1 hour max
+  return Math.min(exponentialDelay, maxDelay);
+};

 // Calculate exponential backoff delay
-const baseDelay = 5 * 60 * 1000; // 5 minutes
-const exponentialDelay = baseDelay * Math.pow(2, pending.attempts - 1);
-const maxDelay = 60 * 60 * 1000; // 1 hour max
-const nextRetryDelay = Math.min(exponentialDelay, maxDelay);
+const nextRetryDelay = calculateNextRetryDelay(pending.attempts);

97-111: Enhance error handling with type safety.

The enhanced error handling is a good improvement, but consider adding type safety for the payment object structure and error types.

 // Enhanced error handling for different payment failure types
-if (payment && typeof payment === 'object' && 'error' in payment) {
+if (payment && typeof payment === 'object' && 'error' in payment && typeof payment.error === 'string') {
   pending.last_error = payment.error as string;
   
-  if (payment.error === 'TIMEOUT') {
+  const errorType = payment.error.toUpperCase();
+  if (errorType === 'TIMEOUT') {
     logger.warn(`Payment timeout for order ${order._id}, attempt ${pending.attempts}`);
-  } else if (payment.error === 'ROUTING_FAILED') {
+  } else if (errorType === 'ROUTING_FAILED') {
     logger.warn(`Routing failed for order ${order._id}, attempt ${pending.attempts}`);
   } else {
     logger.error(`Payment failed for order ${order._id}, attempt ${pending.attempts}, error: ${payment.error}`);
   }
ln/pay_request.ts (2)

26-91: Consider improving type safety for the return value.

The function returns different types: false, invoice object, payment object, or error object. This inconsistent typing could lead to runtime errors and makes it harder for callers to handle the response correctly.

Consider defining a consistent return type:

type PayRequestResult = 
  | { success: true; payment: any }
  | { success: false; error: 'INVALID_INVOICE' | 'EXPIRED' | 'TIMEOUT' | 'ROUTING_FAILED' | 'INSUFFICIENT_BALANCE' | 'UNKNOWN'; message?: string };

This would make error handling more predictable and type-safe throughout the codebase.


163-164: Simplify the complex ternary expression for better readability.

The nested ternary expression is hard to read and maintain.

         attempts: 1,
-        last_error: payment && typeof payment === 'object' && 'error' in payment ? payment.error as string : 'UNKNOWN',
+        last_error: (payment && typeof payment === 'object' && 'error' in payment) 
+          ? (payment.error as string) 
+          : 'UNKNOWN',

Or even better, extract the logic:

+      const errorType = (payment && typeof payment === 'object' && 'error' in payment) 
+        ? payment.error as string 
+        : 'UNKNOWN';
       const pp = new PendingPayment({
         amount: order.amount,
         payment_request: order.buyer_invoice,
         user_id: buyerUser._id,
         description: order.description,
         hash: order.hash,
         order_id: order._id,
         attempts: 1,
-        last_error: payment && typeof payment === 'object' && 'error' in payment ? payment.error as string : 'UNKNOWN',
+        last_error: errorType,
       });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ee5069 and 55ac642.

📒 Files selected for processing (6)
  • .env-sample (1 hunks)
  • app.ts (1 hunks)
  • jobs/pending_payments.ts (4 hunks)
  • ln/pay_request.ts (5 hunks)
  • logger.ts (1 hunks)
  • models/pending_payment.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
app.ts (1)
bot/modules/community/communityContext.ts (1)
  • CommunityContext (10-14)
jobs/pending_payments.ts (2)
models/index.ts (1)
  • Order (11-11)
logger.ts (1)
  • logger (53-53)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
.env-sample (1)

64-68: LGTM! Clean timeout configuration additions.

The new environment variables for configurable timeouts are well-documented with clear comments and reasonable default values. The naming convention is consistent with existing variables.

models/pending_payment.ts (1)

16-17: LGTM! Good additions for error tracking and retry scheduling.

The new fields last_error and next_retry properly support the enhanced retry mechanism with error tracking.

logger.ts (1)

26-35: LGTM! Well-structured timeout logging utility.

The logTimeout function provides excellent structured logging for timeout events with all necessary context data.

jobs/pending_payments.ts (2)

17-17: LGTM! Proper retry scheduling implementation.

The next_retry filter ensures pending payments are only processed when their retry time has arrived, supporting the exponential backoff strategy.


115-115: LGTM! Correct operator change for attempt limit.

Changing from === to >= ensures that no attempts beyond the configured limit are processed, which is the correct behavior.

ln/pay_request.ts (2)

137-154: Well-implemented error handling with proper categorization!

The differentiated handling of timeout, routing failures, and other errors provides good visibility into payment failure reasons, which will help with debugging and monitoring. This aligns perfectly with the PR objectives for improved error recovery.


42-44: Verify that the LN_PATHFINDING_TIMEOUT environment variable is documented.

Since this is a new configurable timeout, ensure it's properly documented in the environment configuration.

#!/bin/bash
# Description: Check if LN_PATHFINDING_TIMEOUT is documented in environment files

# Check for documentation in .env files and README
fd -t f -e md -e env -e sample | xargs rg -l "LN_PATHFINDING_TIMEOUT"

# Check the actual usage and default value
rg -A 2 -B 2 "LN_PATHFINDING_TIMEOUT"

Comment thread ln/pay_request.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
CLAUDE.md (2)

60-65: Minor grammar polish in the escrow flow steps

Step texts miss determiners (“The”, “a/an”) which slightly hurts readability.

-1. Seller creates order
-2. Buyer takes order, seller pays hold invoice
+1. The seller creates an order
+2. The buyer takes the order and the seller pays a hold invoice

25-29: Duplicate “Testing” sections may confuse readers

There is a testing subsection under both Development Commands and Architecture. Consider merging or renaming one (e.g., “Test Setup”) to avoid redundancy.

Also applies to: 88-90

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55ac642 and 17d53db.

📒 Files selected for processing (2)
  • CLAUDE.md (1 hunks)
  • ln/pay_request.ts (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • ln/pay_request.ts
🧰 Additional context used
🪛 LanguageTool
CLAUDE.md

[uncategorized] ~61-~61: You might be missing the article “an” here.
Context: ...for trustless escrow: 1. Seller creates order 2. Buyer takes order, seller pays hold ...

(AI_EN_LECTOR_MISSING_DETERMINER_AN)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: ci_to_main

Comment thread CLAUDE.md
Comment thread jobs/pending_payments.ts
@grunch
grunch merged commit f989cd2 into main Jun 26, 2025
7 checks passed
@grunch
grunch deleted the fix/timeout-handling-improvements branch June 26, 2025 19:16
Comment thread jobs/pending_payments.ts
const exponentialDelay = baseDelay * Math.pow(2, pending.attempts - 1);
const maxDelay = 60 * 60 * 1000; // 1 hour max
const nextRetryDelay = Math.min(exponentialDelay, maxDelay);
pending.next_retry = new Date(Date.now() + nextRetryDelay);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@grunch this piece of code is duplicated, should it be extracted as a function?

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.

3 participants