Skip to content

Feat/marker pdf chunking - #297

Merged
Ahmath-Gadji merged 3 commits into
devfrom
feat/marker_pdf_chunking
Apr 10, 2026
Merged

Feat/marker pdf chunking#297
Ahmath-Gadji merged 3 commits into
devfrom
feat/marker_pdf_chunking

Conversation

@Ahmath-Gadji

@Ahmath-Gadji Ahmath-Gadji commented Apr 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Page chunking for Marker PDF processing: Large PDFs are split into fixed-size page chunks (MARKER_CHUNK_SIZE, default 10) and dispatched concurrently across all available Marker workers. This reduces per-worker GPU memory spikes (~2.5 GB vs 4+ GB unchunked) and enables safely scaling MARKER_MAX_PROCESSES without OOM risk.
  • Health check fix: Replaced the unreliable process-counting health check (get_current_pool_size) with is_pool_broken(), which checks the executor's broken state instead of counting live subprocesses. The previous approach falsely triggered pool resets when workers were simply busy.
  • VDB_ENABLE_INSERTION env var: Allows disabling vector database insertion while still processing documents. Useful for benchmarking and testing.
  • Removed MARKER_MIN_PROCESSES: No longer needed after the health check rework. Cleaned up from config, code, docs, and Helm chart.

Benchmark results

Chunk size Duration Max GPU spike Spike duration
30 16m 27s 2.2 - 4.0 GB 5s to ~2 min
20 16m 44s 2.2 - 3.0 GB 5s to ~1 min
10 17m 29s 1.9 - 2.5 GB 5s - 30s

Summary by CodeRabbit

  • New Features

    • PDF page chunking for parallel processing (default chunk size: 10) to reduce per-worker GPU memory spikes
    • Toggle to enable/disable vector database insertion
  • Documentation

    • Added a benchmark report on page-chunking performance and GPU behavior
    • Updated environment variable docs to include MARKER_CHUNK_SIZE and VDB_ENABLE_INSERTION
  • Configuration

    • Removed MARKER_MIN_PROCESSES setting
    • Updated deployment/values to reflect these changes

@coderabbitai

coderabbitai Bot commented Apr 8, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces MARKER_MIN_PROCESSES with MARKER_CHUNK_SIZE to split PDFs into page-range chunks processed in parallel; adds pypdfium2 page counting; refactors pool health to detect broken executors; adds VDB_ENABLE_INSERTION; updates docs, helm values, and config schemas accordingly.

Changes

Cohort / File(s) Summary
Configuration & Models
conf/config.yaml, openrag/config/loader.py, openrag/config/models.py
Removed marker_min_processes; added marker_chunk_size (default 10) and VDB_ENABLE_INSERTION env override/field.
Marker PDF Loader Implementation
openrag/components/indexer/loaders/pdf_loaders/marker.py
Added pypdfium2 page counting; MarkerWorker.process_pdf accepts page_range; added chunk creation (_create_chunks), _get_page_count, _process_chunk; parallel per-chunk processing and ordered markdown/images reassembly; replaced liveness counting with is_pool_broken().
Docs & Benchmarks
docs/content/docs/documentation/env_vars.md, docs/content/docs/documentation/deploy_ray_cluster.md, benchmarks/marker/marker_page_chunking.md
Removed MARKER_MIN_PROCESSES references; added MARKER_CHUNK_SIZE and VDB_ENABLE_INSERTION docs; added Marker page-chunking benchmark doc.
Helm Values
charts/openrag-stack/values.yaml
Removed MARKER_MIN_PROCESSES: "3" from shared env.config.
Project Dependencies
pyproject.toml
Added runtime dependency pypdfium2>=4.30.0.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant MarkerPool as MarkerPool
    participant PdfLib as pypdfium2
    participant Executor as ProcessPoolExecutor
    participant Worker as MarkerWorker

    Client->>MarkerPool: process_pdf(file_path)
    MarkerPool->>PdfLib: get_page_count(file_path)
    PdfLib-->>MarkerPool: total_pages
    MarkerPool->>MarkerPool: _create_chunks(total_pages, marker_chunk_size)
    MarkerPool-->>MarkerPool: chunks = [range0, range1, ...]

    par process chunks
        MarkerPool->>Executor: submit(_process_chunk, file_path, page_range=rangeN)
        Executor->>Worker: process_pdf(file_path, page_range=rangeN)
        Worker-->>Executor: {markdown_chunk, images_chunk}
        Executor-->>MarkerPool: chunk_result_N
    end

    MarkerPool->>MarkerPool: reassemble(chunk_results in order)
    MarkerPool-->>Client: {full_markdown, merged_images}
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Pages sliced in neat array,
Workers munch and hop away.
Chunks converge in tidy line,
Memory eases, outputs shine.
A rabbit cheers — the parser’s fine. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feat/marker pdf chunking' is directly related to the main change: implementing page chunking for Marker PDF processing to reduce GPU memory spikes and improve worker scaling.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/marker_pdf_chunking

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.

@Ahmath-Gadji
Ahmath-Gadji requested a review from EnjoyBacon7 April 8, 2026 15:08

@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.

Actionable comments posted: 4

🧹 Nitpick comments (1)
openrag/components/indexer/loaders/pdf_loaders/marker.py (1)

155-159: Avoid hard-depending on ProcessPoolExecutor._broken.

_broken is private stdlib state. If the target Python runtime changes or removes it, this health check will start raising instead of recreating the pool. At minimum guard it with getattr(...); longer-term it would be safer to reinitialize from submit/result failures instead of probing internals.

🛡️ Minimal defensive guard
-        return self.executor is None or self.executor._broken
+        return self.executor is None or bool(getattr(self.executor, "_broken", False))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@openrag/components/indexer/loaders/pdf_loaders/marker.py` around lines 155 -
159, The is_pool_broken method currently accesses the private attribute
executor._broken; change it to defensively check using getattr(self.executor,
"_broken", False) (and still treat executor is None as broken) so it won't raise
if _broken is absent, i.e., return self.executor is None or
getattr(self.executor, "_broken", False); consider a follow-up to remove probing
internals entirely by detecting failures on submit/result and reinitializing the
pool then.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@benchmarks/marker/marker_page_chunking.md`:
- Around line 53-55: The markdown fenced block containing the expression
"available_gpu_mem >= max_spike * num_workers + marker_model_gpu_size +
other_gpu_processes" should be changed from an untyped fence to a typed one to
satisfy markdownlint (MD040); update the fence from ``` to ```text around that
expression so the block is explicitly marked as text (locate the fenced block
that holds the GPU capacity expression shown in the diff).

In `@docs/content/docs/documentation/env_vars.md`:
- Around line 42-50: The documentation currently hardcodes performance numbers
for MARKER_CHUNK_SIZE (e.g., "up to 10x faster" and "~1 GB per worker")—update
the MARKER_CHUNK_SIZE note to either (a) reference the specific benchmark and
its test conditions (link or cite the bench file and state worker count,
environment, and chunk size used) when keeping numbers, or (b) remove precise
numeric claims and replace them with qualitative guidance (e.g., "significantly
faster" and "reduces peak memory usage") plus a suggestion to consult
benchmarks/marker/marker_page_chunking.md for measured results; adjust the
paragraph mentioning MARKER_MAX_TASKS_PER_CHILD accordingly so it remains
generic guidance rather than a hard claim.
- Line 176: Update the docs row for `VDB_ENABLE_INSERTION`: change the default
from `false` to `true` to match the actual defaults in
`openrag/config/models.py` (where `vectordb.enable` is set) and
`conf/config.yaml`; also correct the typo "texting" to "testing" in the
description. Ensure the table cell for `VDB_ENABLE_INSERTION` reflects `true`
and the explanation reads "...Useful for testing."

In `@openrag/components/indexer/loaders/pdf_loaders/marker.py`:
- Around line 253-255: The current call to
asyncio.gather(*[self._process_chunk(...) for ...]) lets other chunk coroutines
keep running if one fails; change this to create explicit asyncio.Task objects
for each self._process_chunk call (e.g., tasks =
[asyncio.create_task(self._process_chunk(...)) for ...]), use
asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION) to detect the first
failure, cancel all pending tasks (for t in pending: t.cancel()), then await
asyncio.gather(*tasks, return_exceptions=False) or re-raise the caught exception
so the failure propagates and sibling tasks are not left running; update the
code around results = await asyncio.gather(...) to implement this pattern
referencing self._process_chunk, chunks, tasks, pending, and FIRST_EXCEPTION.

---

Nitpick comments:
In `@openrag/components/indexer/loaders/pdf_loaders/marker.py`:
- Around line 155-159: The is_pool_broken method currently accesses the private
attribute executor._broken; change it to defensively check using
getattr(self.executor, "_broken", False) (and still treat executor is None as
broken) so it won't raise if _broken is absent, i.e., return self.executor is
None or getattr(self.executor, "_broken", False); consider a follow-up to remove
probing internals entirely by detecting failures on submit/result and
reinitializing the pool then.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 418a8d6e-0506-498f-a231-ad0856e2c060

📥 Commits

Reviewing files that changed from the base of the PR and between 93ac130 and 1b6fa85.

📒 Files selected for processing (13)
  • benchmarks/marker/marker_page_chunking.md
  • benchmarks/workspace/README.md
  • benchmarks/workspace/docker-compose.yml
  • benchmarks/workspace/requirements.txt
  • benchmarks/workspace/results_workspace.md
  • benchmarks/workspace/workspace.py
  • charts/openrag-stack/values.yaml
  • conf/config.yaml
  • docs/content/docs/documentation/deploy_ray_cluster.md
  • docs/content/docs/documentation/env_vars.md
  • openrag/components/indexer/loaders/pdf_loaders/marker.py
  • openrag/config/loader.py
  • openrag/config/models.py
💤 Files with no reviewable changes (2)
  • charts/openrag-stack/values.yaml
  • docs/content/docs/documentation/deploy_ray_cluster.md

Comment thread benchmarks/marker/marker_page_chunking.md Outdated
Comment thread docs/content/docs/documentation/env_vars.md
Comment thread docs/content/docs/documentation/env_vars.md Outdated
Comment thread openrag/components/indexer/loaders/pdf_loaders/marker.py Outdated
…kers

Split large PDFs into configurable page chunks (MARKER_CHUNK_SIZE) and
dispatch them to available workers concurrently, reducing memory spikes
and enabling safer scaling of worker count. Also replace the unreliable
process-counting health check with executor broken-state detection, and
remove the now-unused MARKER_MIN_PROCESSES config.
@Ahmath-Gadji
Ahmath-Gadji force-pushed the feat/marker_pdf_chunking branch from 22d96ec to e3a56d2 Compare April 8, 2026 16:11

@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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@openrag/components/indexer/loaders/pdf_loaders/marker.py`:
- Around line 217-234: The worker dequeued from self._queue in the
_process_chunk method can be lost if ensure_worker_pool_healthy raises, so
ensure the worker is always requeued: after obtaining worker = await
self._queue.get(), immediately wrap the subsequent logic in a try/finally (or
catch exceptions from ensure_worker_pool_healthy and re-put the worker before
re-raising) so that await self._queue.put(worker) in the finally block always
runs; keep the processing call to worker.process_pdf.remote and
call_ray_actor_with_timeout inside the try block and rethrow any errors after
requeuing.
- Line 7: The file marker.py imports pypdfium2 directly (import pypdfium2), but
pypdfium2 is only a transitive dependency; add pypdfium2 as a direct dependency
in pyproject.toml under [tool.poetry.dependencies] (or the project's dependency
section) with an appropriate version constraint, so the direct import in
marker.py is guaranteed to resolve and not break if marker-pdf drops it.
- Around line 211-215: The health-check calls in ensure_worker_pool_healthy are
calling the actor methods directly and can block; change both calls to use
call_ray_actor_with_timeout so they follow the same timeout/cancellation path as
process_pdf (see process_pdf usage). Specifically, replace awaiting
worker.is_pool_broken.remote() and worker.setup_mp.remote() with calls wrapped
by call_ray_actor_with_timeout(...) passing the same timeout constant/handler
used by process_pdf so the actor calls time out and free the queue slot if the
actor is wedged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c0de7cd3-3264-4dfa-a146-9cfbfbed8caf

📥 Commits

Reviewing files that changed from the base of the PR and between 22d96ec and e3a56d2.

📒 Files selected for processing (13)
  • benchmarks/marker/marker_page_chunking.md
  • benchmarks/workspace/README.md
  • benchmarks/workspace/docker-compose.yml
  • benchmarks/workspace/requirements.txt
  • benchmarks/workspace/results_workspace.md
  • benchmarks/workspace/workspace.py
  • charts/openrag-stack/values.yaml
  • conf/config.yaml
  • docs/content/docs/documentation/deploy_ray_cluster.md
  • docs/content/docs/documentation/env_vars.md
  • openrag/components/indexer/loaders/pdf_loaders/marker.py
  • openrag/config/loader.py
  • openrag/config/models.py
💤 Files with no reviewable changes (2)
  • docs/content/docs/documentation/deploy_ray_cluster.md
  • charts/openrag-stack/values.yaml
✅ Files skipped from review due to trivial changes (1)
  • benchmarks/marker/marker_page_chunking.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • openrag/config/loader.py

Comment thread openrag/components/indexer/loaders/pdf_loaders/marker.py
Comment thread openrag/components/indexer/loaders/pdf_loaders/marker.py Outdated
Comment thread openrag/components/indexer/loaders/pdf_loaders/marker.py
@EnjoyBacon7
EnjoyBacon7 force-pushed the feat/marker_pdf_chunking branch from e3a56d2 to 3aebdd1 Compare April 9, 2026 07:47
@Ahmath-Gadji
Ahmath-Gadji force-pushed the feat/marker_pdf_chunking branch from 3aebdd1 to c53d4b2 Compare April 9, 2026 07:57
@Ahmath-Gadji Ahmath-Gadji added the feat Add a new feature label Apr 9, 2026

@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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@openrag/components/indexer/loaders/pdf_loaders/marker.py`:
- Around line 193-197: The _get_page_count function currently opens a
PdfDocument with pypdfium2.PdfDocument(file_path) and calls pdf.close()
manually, which can leak the file handle if len(pdf) raises; change it to use a
context manager (with pypdfium2.PdfDocument(file_path) as pdf:) so the document
is always closed on error and simply return len(pdf) from inside the with block
to ensure proper resource cleanup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 39f328bb-ca4c-43d3-9431-c7f78e711fea

📥 Commits

Reviewing files that changed from the base of the PR and between 3aebdd1 and c53d4b2.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • benchmarks/marker/marker_page_chunking.md
  • benchmarks/workspace/README.md
  • benchmarks/workspace/docker-compose.yml
  • benchmarks/workspace/requirements.txt
  • benchmarks/workspace/results_workspace.md
  • benchmarks/workspace/workspace.py
  • openrag/components/indexer/loaders/pdf_loaders/marker.py
  • pyproject.toml
✅ Files skipped from review due to trivial changes (2)
  • pyproject.toml
  • benchmarks/marker/marker_page_chunking.md

Comment thread openrag/components/indexer/loaders/pdf_loaders/marker.py Outdated
@EnjoyBacon7
EnjoyBacon7 force-pushed the feat/marker_pdf_chunking branch from c53d4b2 to f91f196 Compare April 9, 2026 08:07
@EnjoyBacon7
EnjoyBacon7 force-pushed the feat/marker_pdf_chunking branch from f91f196 to 6989e64 Compare April 9, 2026 08:12
@Ahmath-Gadji
Ahmath-Gadji merged commit 064ac3c into dev Apr 10, 2026
4 checks passed
@Ahmath-Gadji
Ahmath-Gadji deleted the feat/marker_pdf_chunking branch April 10, 2026 09:13
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.

1 participant