- Add _check_single_worker_mode() to startup.py that detects and rejects multi-worker configurations, raising a clear RuntimeError with instructions - Set BANGUI_WORKERS=1 as default in Dockerfile.backend - Document single-worker requirement in compose.prod.yml - Add 'Deployment Constraints' section to Architekture.md explaining why single-worker mode is required and detailing future multi-worker support - Add '9.1 Background Tasks and Scheduler Architecture' section to Backend-Development.md documenting task structure and single-worker requirement - Add comprehensive test suite (test_startup.py) covering all scenarios: allows single worker, rejects multi-worker, validates config format, and verifies informative error messages This fix addresses TASK-002 which identified that in-process APScheduler is unsafe in multi-worker deployments due to each worker creating independent scheduler instances, causing duplicate background job execution. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
58 lines
2.1 KiB
Python
58 lines
2.1 KiB
Python
"""Unit tests for application startup and resource initialization."""
|
|
|
|
import os
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from app.startup import _check_single_worker_mode
|
|
|
|
|
|
def test_check_single_worker_mode_allows_workers_1() -> None:
|
|
"""Single-worker mode is allowed and no error is raised."""
|
|
with patch.dict(os.environ, {"BANGUI_WORKERS": "1"}):
|
|
# Should not raise
|
|
_check_single_worker_mode()
|
|
|
|
|
|
def test_check_single_worker_mode_allows_no_env_var() -> None:
|
|
"""When BANGUI_WORKERS is not set, no error is raised."""
|
|
with patch.dict(os.environ, {}, clear=False):
|
|
# Remove BANGUI_WORKERS if it exists
|
|
os.environ.pop("BANGUI_WORKERS", None)
|
|
# Should not raise
|
|
_check_single_worker_mode()
|
|
|
|
|
|
def test_check_single_worker_mode_rejects_workers_2() -> None:
|
|
"""Multi-worker mode (N=2) raises a clear RuntimeError."""
|
|
with patch.dict(os.environ, {"BANGUI_WORKERS": "2"}), pytest.raises(
|
|
RuntimeError, match="cannot run with multiple workers"
|
|
):
|
|
_check_single_worker_mode()
|
|
|
|
|
|
def test_check_single_worker_mode_rejects_workers_4() -> None:
|
|
"""Multi-worker mode (N=4) raises a clear RuntimeError."""
|
|
with patch.dict(os.environ, {"BANGUI_WORKERS": "4"}), pytest.raises(
|
|
RuntimeError, match="cannot run with multiple workers"
|
|
):
|
|
_check_single_worker_mode()
|
|
|
|
|
|
def test_check_single_worker_mode_rejects_invalid_workers_value() -> None:
|
|
"""Invalid BANGUI_WORKERS value raises a clear RuntimeError."""
|
|
with patch.dict(os.environ, {"BANGUI_WORKERS": "not-a-number"}), pytest.raises(
|
|
RuntimeError, match="must be an integer"
|
|
):
|
|
_check_single_worker_mode()
|
|
|
|
|
|
def test_check_single_worker_mode_error_message_is_informative() -> None:
|
|
"""Error message includes instructions and reference to documentation."""
|
|
with patch.dict(os.environ, {"BANGUI_WORKERS": "2"}), pytest.raises(RuntimeError) as exc_info:
|
|
_check_single_worker_mode()
|
|
error_message = str(exc_info.value)
|
|
assert "multiple workers" in error_message
|
|
assert "Architekture.md" in error_message
|