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
- Add exponential backoff instead of fixed 1-second delay
- Add jitter to prevent thundering herd
- Make retry parameters configurable via
PageIndexConfig
Files to Modify
src/pageindex/llm.py
- Optionally create
src/pageindex/retry.py for reusable retry utilities
Problem
chat()andchat_with_finish_reason()have nearly identical retry logic (~25 lines each):Proposed Solution
Option A: Retry decorator
Option B: Helper method
Additional Improvements
PageIndexConfigFiles to Modify
src/pageindex/llm.pysrc/pageindex/retry.pyfor reusable retry utilities