fix: validate timeout cascade ordering in Settings (#62)

Enforce document_timeout < lock_timeout < conversion_timeout at startup.
Prevents inverted timeout configurations that cause unpredictable behavior.
This commit is contained in:
Pier-Jean Malandrino 2026-04-07 17:04:09 +02:00
parent 1657bce1f0
commit 8ea0cebc16
2 changed files with 32 additions and 2 deletions

View file

@ -46,6 +46,18 @@ class Settings:
errors.append(
f"default_table_mode must be 'accurate' or 'fast' (got '{self.default_table_mode}')"
)
# Timeout cascade: document_timeout < lock_timeout < conversion_timeout
if self.document_timeout > 0 and self.lock_timeout > 0 and self.conversion_timeout > 0:
if self.document_timeout >= self.lock_timeout:
errors.append(
f"document_timeout ({self.document_timeout}s) must be "
f"< lock_timeout ({self.lock_timeout}s)"
)
if self.lock_timeout >= self.conversion_timeout:
errors.append(
f"lock_timeout ({self.lock_timeout}s) must be "
f"< conversion_timeout ({self.conversion_timeout}s)"
)
if errors:
raise ValueError("Invalid settings:\n " + "\n ".join(errors))

View file

@ -79,6 +79,22 @@ class TestSettingsValidation:
with pytest.raises(ValueError, match="default_table_mode must be"):
Settings(default_table_mode="turbo")
def test_cascade_document_ge_lock_rejected(self):
import pytest
with pytest.raises(ValueError, match=r"document_timeout.*< lock_timeout"):
Settings(document_timeout=400.0, lock_timeout=300, conversion_timeout=900)
def test_cascade_lock_ge_conversion_rejected(self):
import pytest
with pytest.raises(ValueError, match=r"lock_timeout.*< conversion_timeout"):
Settings(document_timeout=100.0, lock_timeout=900, conversion_timeout=900)
def test_cascade_valid_ordering_accepted(self):
s = Settings(document_timeout=60.0, lock_timeout=300, conversion_timeout=900)
assert s.document_timeout < s.lock_timeout < s.conversion_timeout
def test_multiple_errors_reported(self):
import pytest
@ -94,8 +110,9 @@ class TestSettingsFromEnv:
monkeypatch.setenv("DEPLOYMENT_MODE", "huggingface")
monkeypatch.setenv("DOCLING_SERVE_URL", "http://serve:9000")
monkeypatch.setenv("DOCLING_SERVE_API_KEY", "secret-key")
monkeypatch.setenv("CONVERSION_TIMEOUT", "120")
monkeypatch.setenv("CONVERSION_TIMEOUT", "1200")
monkeypatch.setenv("DOCUMENT_TIMEOUT", "60.0")
monkeypatch.setenv("LOCK_TIMEOUT", "600")
monkeypatch.setenv("MAX_PAGE_COUNT", "20")
monkeypatch.setenv("UPLOAD_DIR", "/data/uploads")
monkeypatch.setenv("DB_PATH", "/data/test.db")
@ -108,7 +125,8 @@ class TestSettingsFromEnv:
assert s.deployment_mode == "huggingface"
assert s.docling_serve_url == "http://serve:9000"
assert s.docling_serve_api_key == "secret-key"
assert s.conversion_timeout == 120
assert s.conversion_timeout == 1200
assert s.lock_timeout == 600
assert s.document_timeout == 60.0
assert s.max_page_count == 20
assert s.upload_dir == "/data/uploads"