Skip to content

Extract duplicate retry logic in LLM client #6

Description

@NP-compete

Problem

chat() and chat_with_finish_reason() have nearly identical retry logic (~25 lines each):

def chat(self, prompt: str, max_retries: int = 10, ...):
    for attempt in range(max_retries):
        try:
            # ... API call ...
        except Exception as e:
            logger.warning(f"Attempt {attempt + 1}/{max_retries} failed: {e}")
            if attempt < max_retries - 1:
                time.sleep(1)
            else:
                raise

def chat_with_finish_reason(self, prompt: str, max_retries: int = 10, ...):
    # Same retry logic duplicated

Proposed Solution

Option A: Retry decorator

def with_retry(max_retries: int = 10, delay: float = 1.0):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt < max_retries - 1:
                        logger.warning(f"Attempt {attempt + 1} failed: {e}")
                        time.sleep(delay)
                    else:
                        raise
        return wrapper
    return decorator

Option B: Helper method

def _call_with_retry(self, call_fn, max_retries: int = 10):
    for attempt in range(max_retries):
        try:
            return call_fn()
        except Exception as e:
            # ... retry logic ...

Additional Improvements

  1. Add exponential backoff instead of fixed 1-second delay
  2. Add jitter to prevent thundering herd
  3. Make retry parameters configurable via PageIndexConfig

Files to Modify

  • src/pageindex/llm.py
  • Optionally create src/pageindex/retry.py for reusable retry utilities

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions