fix: add document_timeout to PdfPipelineOptions (C1)

Docling's native document_timeout is the only mechanism that can
interrupt processing inside a blocked thread (OCR, table extraction).
Without it, asyncio.wait_for cannot stop a frozen conversion.

Configurable via DOCUMENT_TIMEOUT env var (default: 120s).

Closes #57 (C1)
This commit is contained in:
Pier-Jean Malandrino 2026-04-07 14:37:51 +02:00
parent 5b6f138164
commit 4c76101142
4 changed files with 8 additions and 0 deletions

View file

@ -42,6 +42,7 @@ from domain.value_objects import (
PageElement,
)
from infra.bbox import to_topleft_list
from infra.settings import settings
logger = logging.getLogger(__name__)
@ -102,6 +103,7 @@ def _build_docling_converter(options: ConversionOptions) -> DoclingConverter:
generate_page_images=options.generate_page_images,
generate_picture_images=options.generate_picture_images,
images_scale=options.images_scale,
document_timeout=settings.document_timeout,
)
return DoclingConverter(

View file

@ -14,6 +14,7 @@ class Settings:
docling_serve_url: str = "http://localhost:5001"
docling_serve_api_key: str | None = None
conversion_timeout: int = 900
document_timeout: float = 120.0 # Docling-level per-document timeout (seconds)
max_concurrent_analyses: int = 3
max_page_count: int = 0 # 0 = unlimited
upload_dir: str = "./uploads"
@ -33,6 +34,7 @@ class Settings:
docling_serve_url=os.environ.get("DOCLING_SERVE_URL", "http://localhost:5001"),
docling_serve_api_key=os.environ.get("DOCLING_SERVE_API_KEY"),
conversion_timeout=int(os.environ.get("CONVERSION_TIMEOUT", "900")),
document_timeout=float(os.environ.get("DOCUMENT_TIMEOUT", "120.0")),
max_concurrent_analyses=int(os.environ.get("MAX_CONCURRENT_ANALYSES", "3")),
max_page_count=int(os.environ.get("MAX_PAGE_COUNT", "0")),
upload_dir=os.environ.get("UPLOAD_DIR", "./uploads"),

View file

@ -53,6 +53,7 @@ class TestBuildConverter:
assert opts.generate_page_images is False
assert opts.generate_picture_images is False
assert opts.images_scale == 1.0
assert opts.document_timeout is not None
def test_ocr_disabled(self):
conv = build_converter(ConversionOptions(do_ocr=False))

View file

@ -14,6 +14,7 @@ class TestSettingsDefaults:
assert s.docling_serve_url == "http://localhost:5001"
assert s.docling_serve_api_key is None
assert s.conversion_timeout == 900
assert s.document_timeout == 120.0
assert s.max_page_count == 0
assert s.upload_dir == "./uploads"
assert s.db_path == "./data/docling_studio.db"
@ -36,6 +37,7 @@ class TestSettingsFromEnv:
monkeypatch.setenv("DOCLING_SERVE_URL", "http://serve:9000")
monkeypatch.setenv("DOCLING_SERVE_API_KEY", "secret-key")
monkeypatch.setenv("CONVERSION_TIMEOUT", "120")
monkeypatch.setenv("DOCUMENT_TIMEOUT", "60.0")
monkeypatch.setenv("MAX_PAGE_COUNT", "20")
monkeypatch.setenv("UPLOAD_DIR", "/data/uploads")
monkeypatch.setenv("DB_PATH", "/data/test.db")
@ -49,6 +51,7 @@ class TestSettingsFromEnv:
assert s.docling_serve_url == "http://serve:9000"
assert s.docling_serve_api_key == "secret-key"
assert s.conversion_timeout == 120
assert s.document_timeout == 60.0
assert s.max_page_count == 20
assert s.upload_dir == "/data/uploads"
assert s.db_path == "/data/test.db"