Skip to content

Marker retries - #304

Merged
Ahmath-Gadji merged 2 commits into
devfrom
MarkerRetries
Apr 15, 2026
Merged

Marker retries#304
Ahmath-Gadji merged 2 commits into
devfrom
MarkerRetries

Conversation

@EnjoyBacon7

@EnjoyBacon7 EnjoyBacon7 commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

Release Notes

  • Chores
    • Enhanced audio transcription and PDF document processing pipelines with configurable timeout and exponential-backoff retry mechanisms to improve resilience against transient failures and service interruptions.

Extract retry_with_backoff() helper in components/ray_utils.py and wire
it into MarkerPool, DoclingPool, and WhisperPool so transient worker
failures (GPU OOM, broken ProcessPoolExecutor, etc.) retry per-task
instead of failing the whole document.

Retries happen at the pool layer so each attempt re-acquires a worker
from the queue and re-runs health checks. Marker keeps per-chunk
granularity — a failed chunk retries without re-running sibling chunks
or post-processing.

Also adds timeout coverage to DoclingPool and WhisperPool, which
previously awaited actor.remote() directly with no timeout or
ray.cancel on caller cancellation.

Per-loader knobs (marker/docling default 3 retries; whisper default 1
since failures there are often deterministic like corrupt audio).
@EnjoyBacon7

Copy link
Copy Markdown
Collaborator Author

@CodeRabbit?

@EnjoyBacon7
EnjoyBacon7 marked this pull request as ready for review April 14, 2026 14:42

@Ahmath-Gadji Ahmath-Gadji left a comment

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.

LGTM

@paultranvan

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@paultranvan

paultranvan commented Apr 15, 2026

Copy link
Copy Markdown
Collaborator

@coderabbitai review now you're awake

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

@paultranvan Sure, I'm on it! Triggering a review of the PR now. 🐇

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown

@paultranvan Sure thing! I'll review the PR right away. 🐇

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR adds configurable timeout and exponential backoff retry mechanisms to three Ray-based file processing components: local whisper (audio transcription), marker (PDF chunking), and docling (PDF conversion). A new retry_with_backoff utility function is introduced, configuration parameters are added, and the three loaders are updated to wrap Ray actor calls with this error-handling logic.

Changes

Cohort / File(s) Summary
Configuration
conf/config.yaml, openrag/config/models.py
Added timeout and retry/backoff parameters for local_whisper (whisper_timeout, whisper_max_task_retry, whisper_retry_base_delay), marker (marker_max_task_retry, marker_retry_base_delay), and docling (docling_timeout, docling_max_task_retry, docling_retry_base_delay) configurations.
Ray Utilities
openrag/components/ray_utils.py
New retry_with_backoff async helper function implementing exponential-backoff retries with cancellation propagation, failure logging, and configurable retry count and base delay.
Loader Components
openrag/components/indexer/loaders/audio/local_whisper.py, openrag/components/indexer/loaders/pdf_loaders/marker.py, openrag/components/indexer/loaders/pdf_loaders/docling2.py
Updated Ray actor invocations to wrap calls with call_ray_actor_with_timeout and retry_with_backoff, moving worker/resource management into per-attempt closures and restructuring error handling to support retries.

Sequence Diagram

sequenceDiagram
    participant Loader Component
    participant retry_with_backoff
    participant call_ray_actor_with_timeout
    participant Ray Actor

    Loader Component->>retry_with_backoff: attempt_fn, max_retries, base_delay
    loop For each attempt (0 to max_retries)
        retry_with_backoff->>Loader Component: attempt(attempt_num)
        Loader Component->>Loader Component: acquire resource from queue
        Loader Component->>call_ray_actor_with_timeout: invoke with timeout
        alt Task succeeds within timeout
            call_ray_actor_with_timeout->>Ray Actor: remote call
            Ray Actor-->>call_ray_actor_with_timeout: result
            call_ray_actor_with_timeout-->>Loader Component: return result
            Loader Component->>Loader Component: return resource to queue
            Loader Component-->>retry_with_backoff: success
            retry_with_backoff-->>Loader Component: return result
        else Timeout or Exception
            call_ray_actor_with_timeout-->>Loader Component: raise exception
            Loader Component->>Loader Component: return resource to queue
            Loader Component-->>retry_with_backoff: raise exception
            alt Final attempt
                retry_with_backoff->>retry_with_backoff: log error, re-raise
                retry_with_backoff-->>Loader Component: raise exception
            else Intermediate attempt
                retry_with_backoff->>retry_with_backoff: log warning, wait exponential delay
            end
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 With whispers timed and PDFs retried,
Exponential patience is our guide.
Ray actors dance through timeouts fair,
Backoffs bloom with patient care!
Tasks that fall rise once again,
Resilience hops through code, oh then! 🌟

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'Marker retries' is only partially related to the changeset. While retry logic is indeed added to the Marker component, the PR also introduces retry and timeout handling to Whisper and Docling loaders, and adds a general retry utility. The title focuses only on one aspect of the broader change. Consider a more comprehensive title like 'Add retry and timeout handling to loader pools' to capture the main change affecting all three loaders, not just Marker.
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch MarkerRetries

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

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
openrag/config/models.py (1)

344-351: Consider adding validation constraints for consistency.

The nearby docling_num_gpus and docling_pool_size fields use Field(ge=...) constraints, but the new retry/timeout fields don't. For consistency and safety, consider adding validation to prevent invalid configurations (e.g., negative retries or delays).

🔧 Optional: Add validation constraints
-    marker_max_task_retry: int = 3
-    marker_retry_base_delay: float = 2.0
+    marker_max_task_retry: int = Field(default=3, ge=0)
+    marker_retry_base_delay: float = Field(default=2.0, ge=0)
     docling_num_gpus: float = Field(default=0.01, ge=0)
     docling_pool_size: int = Field(default=1, ge=1)
     docling_max_tasks_per_worker: int = Field(default=2, ge=1)
-    docling_timeout: int = 3600
-    docling_max_task_retry: int = 3
-    docling_retry_base_delay: float = 2.0
+    docling_timeout: int = Field(default=3600, gt=0)
+    docling_max_task_retry: int = Field(default=3, ge=0)
+    docling_retry_base_delay: float = Field(default=2.0, ge=0)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openrag/config/models.py` around lines 344 - 351, Add validation constraints
to the new retry/timeout fields to prevent invalid values: change
marker_max_task_retry and docling_max_task_retry to use Field(default=3, ge=0)
to forbid negatives, set marker_retry_base_delay and docling_retry_base_delay to
Field(default=2.0, ge=0.0) to forbid negative delays, and make docling_timeout
use Field(default=3600, ge=0) (or ge=1 if zero timeout is invalid); update the
Field() calls for these symbols (marker_max_task_retry, marker_retry_base_delay,
docling_timeout, docling_max_task_retry, docling_retry_base_delay) accordingly
to match the pattern used by docling_num_gpus and docling_pool_size.
openrag/components/ray_utils.py (1)

61-66: Type hint should indicate async callable.

The attempt_fn parameter is always awaited (line 76), so the type hint should reflect that it returns an awaitable rather than Any.

🔧 Suggested type hint improvement
+from collections.abc import Awaitable, Callable
-from collections.abc import Callable
 from typing import Any

 ...

 async def retry_with_backoff(
-    attempt_fn: Callable[[int], Any],
+    attempt_fn: Callable[[int], Awaitable[Any]],
     max_retries: int,
     base_delay: float,
     task_description: str = "task",
 ) -> Any:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openrag/components/ray_utils.py` around lines 61 - 66, The retry_with_backoff
signature currently types attempt_fn as Callable[[int], Any] but attempt_fn is
awaited inside the async function; update the signature to use a generic TypeVar
(e.g., T) and annotate attempt_fn as Callable[[int], Awaitable[T]] and the
function return type as -> T; add the necessary imports (TypeVar, Awaitable) and
update any related hints to use the TypeVar so type checkers correctly infer the
awaited result for retry_with_backoff.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@openrag/components/ray_utils.py`:
- Around line 61-66: The retry_with_backoff signature currently types attempt_fn
as Callable[[int], Any] but attempt_fn is awaited inside the async function;
update the signature to use a generic TypeVar (e.g., T) and annotate attempt_fn
as Callable[[int], Awaitable[T]] and the function return type as -> T; add the
necessary imports (TypeVar, Awaitable) and update any related hints to use the
TypeVar so type checkers correctly infer the awaited result for
retry_with_backoff.

In `@openrag/config/models.py`:
- Around line 344-351: Add validation constraints to the new retry/timeout
fields to prevent invalid values: change marker_max_task_retry and
docling_max_task_retry to use Field(default=3, ge=0) to forbid negatives, set
marker_retry_base_delay and docling_retry_base_delay to Field(default=2.0,
ge=0.0) to forbid negative delays, and make docling_timeout use
Field(default=3600, ge=0) (or ge=1 if zero timeout is invalid); update the
Field() calls for these symbols (marker_max_task_retry, marker_retry_base_delay,
docling_timeout, docling_max_task_retry, docling_retry_base_delay) accordingly
to match the pattern used by docling_num_gpus and docling_pool_size.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b0abfa78-da04-42d0-a669-2de5f453069c

📥 Commits

Reviewing files that changed from the base of the PR and between 922714e and c565cfa.

📒 Files selected for processing (6)
  • conf/config.yaml
  • openrag/components/indexer/loaders/audio/local_whisper.py
  • openrag/components/indexer/loaders/pdf_loaders/docling2.py
  • openrag/components/indexer/loaders/pdf_loaders/marker.py
  • openrag/components/ray_utils.py
  • openrag/config/models.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat Add a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants