Merge pull request #878 from cbcoutinho/fix/windows-resource-import-877
fix(documents): guard Unix-only resource import for Windows (#877)
This commit is contained in:
@@ -109,7 +109,6 @@ from nextcloud_mcp_server.config_validators import (
|
||||
validate_configuration,
|
||||
)
|
||||
from nextcloud_mcp_server.context import get_client as get_nextcloud_client
|
||||
from nextcloud_mcp_server.document_processors import get_registry
|
||||
from nextcloud_mcp_server.http import nextcloud_httpx_client
|
||||
from nextcloud_mcp_server.observability import (
|
||||
ObservabilityMiddleware,
|
||||
@@ -159,6 +158,11 @@ def initialize_document_processors():
|
||||
logger.info("Document processing disabled")
|
||||
return
|
||||
|
||||
# Imported lazily so the API startup path never loads the ingest document
|
||||
# stack (document_processors -> pymupdf -> _isolation) unless document
|
||||
# processing is actually enabled -- see #877 / the API-vs-ingest split.
|
||||
from nextcloud_mcp_server.document_processors import get_registry # noqa: PLC0415
|
||||
|
||||
registry = get_registry()
|
||||
registered_count = 0
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ in its process pool.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import resource
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@@ -21,6 +21,15 @@ import anyio
|
||||
import anyio.to_process
|
||||
from anyio import BrokenWorkerProcess
|
||||
|
||||
# ``resource`` is a Unix-only stdlib module -- it does not exist on Windows, and
|
||||
# importing it unconditionally crashed Windows startup (#877). The RLIMIT_AS cap
|
||||
# it provides is a Linux-pod safety measure, not a correctness requirement, so on
|
||||
# platforms without it we fall back to a no-op (``resource is None``).
|
||||
if sys.platform == "win32": # pragma: no cover - win32-only path
|
||||
resource = None
|
||||
else:
|
||||
import resource
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Guard so the address-space limit is applied once per (reused) worker process.
|
||||
@@ -44,10 +53,18 @@ def _apply_mem_limit(mem_limit_mb: int) -> None:
|
||||
|
||||
Applied once per worker process. The hard limit is left untouched (we only
|
||||
lower the soft limit), and we never set a soft limit above the hard limit.
|
||||
|
||||
On a platform without the Unix-only ``resource`` module (e.g. Windows, see
|
||||
#877) the cap is skipped -- the worker still runs, just without the
|
||||
address-space limit.
|
||||
"""
|
||||
global _MEM_LIMIT_APPLIED
|
||||
if _MEM_LIMIT_APPLIED or mem_limit_mb <= 0:
|
||||
return
|
||||
if resource is None:
|
||||
logger.debug("resource module unavailable; skipping RLIMIT_AS cap")
|
||||
_MEM_LIMIT_APPLIED = True
|
||||
return
|
||||
target = mem_limit_mb * 1024 * 1024
|
||||
soft, hard = resource.getrlimit(resource.RLIMIT_AS)
|
||||
soft_target = target if hard == resource.RLIM_INFINITY else min(target, hard)
|
||||
|
||||
@@ -13,10 +13,6 @@ from nextcloud_mcp_server.server.tag_exclusion import (
|
||||
get_excluded_file_paths,
|
||||
is_path_excluded,
|
||||
)
|
||||
from nextcloud_mcp_server.utils.document_parser import (
|
||||
is_parseable_document,
|
||||
parse_document,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -115,6 +111,16 @@ def configure_webdav_tools(mcp: FastMCP):
|
||||
|
||||
content, content_type = await client.webdav.read_file(path)
|
||||
|
||||
# Imported lazily so server startup never loads the document-parsing
|
||||
# stack (document_processors -> pymupdf -> _isolation). That stack is an
|
||||
# ingest-layer concern and, before this, broke Windows startup via a
|
||||
# Unix-only ``import resource`` (#877). It is only needed when a file is
|
||||
# actually read and parsed.
|
||||
from nextcloud_mcp_server.utils.document_parser import ( # noqa: PLC0415
|
||||
is_parseable_document,
|
||||
parse_document,
|
||||
)
|
||||
|
||||
# Check if this is a parseable document (PDF, DOCX, etc.)
|
||||
# is_parseable_document() checks if document processing is enabled
|
||||
if is_parseable_document(content_type):
|
||||
|
||||
@@ -16,7 +16,6 @@ from qdrant_client.models import PointStruct
|
||||
from nextcloud_mcp_server.acl_hash import compute_acl_hash
|
||||
from nextcloud_mcp_server.client import NextcloudClient
|
||||
from nextcloud_mcp_server.config import get_settings
|
||||
from nextcloud_mcp_server.document_processors import get_registry
|
||||
from nextcloud_mcp_server.embedding import get_bm25_service, get_embedding_service
|
||||
from nextcloud_mcp_server.models.deck import DeckCard
|
||||
from nextcloud_mcp_server.observability.metrics import (
|
||||
@@ -707,6 +706,12 @@ async def _index_document(
|
||||
):
|
||||
# The registry runs the tiered PDF pipeline (tier-0 classify ->
|
||||
# tier-1 fast -> OCR escalation) and records classification metrics.
|
||||
# Imported lazily so module import doesn't pull in the document stack
|
||||
# (document_processors -> _isolation, Unix-only ``resource``; see #877).
|
||||
from nextcloud_mcp_server.document_processors import ( # noqa: PLC0415
|
||||
get_registry,
|
||||
)
|
||||
|
||||
registry = get_registry()
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user