Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
"""Best-effort process resource-limit adjustments for long-running services.
|
||||
|
||||
The public helper in this module is shared by the gateway and the dashboard/
|
||||
serve entrypoints. It deliberately has no user-facing environment-variable
|
||||
control: the target comes from the profile's canonical ``config.yaml`` loader.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
from hermes_cli.config_defaults import DEFAULT_CONFIG
|
||||
|
||||
try: # ``resource`` is POSIX-only (and unavailable on Windows).
|
||||
import resource as _resource
|
||||
except (ImportError, ModuleNotFoundError): # pragma: no cover - Windows only
|
||||
_resource = None # type: ignore[assignment]
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_NOFILE_SOFT_LIMIT = int(DEFAULT_CONFIG["runtime"]["nofile_soft_limit"])
|
||||
_MISSING = object()
|
||||
|
||||
|
||||
def _configured_nofile_soft_limit(
|
||||
config: Mapping[str, Any] | None,
|
||||
) -> int | None:
|
||||
"""Resolve ``runtime.nofile_soft_limit`` from a loaded config.
|
||||
|
||||
A missing key uses the default. Explicit ``0``, ``false``, and ``null``
|
||||
disable the adjustment. Other non-integer or negative values are invalid
|
||||
and are ignored (the caller fails open without changing the process limit).
|
||||
"""
|
||||
if config is None:
|
||||
try:
|
||||
# Use Hermes's real, profile-aware loader rather than reading YAML
|
||||
# here. This also applies managed-scope overlays and defaults.
|
||||
from hermes_cli.config import load_config_readonly
|
||||
|
||||
config = load_config_readonly()
|
||||
except Exception:
|
||||
logger.debug("Could not load config for RLIMIT_NOFILE", exc_info=True)
|
||||
return None
|
||||
|
||||
if not isinstance(config, Mapping):
|
||||
return None
|
||||
|
||||
runtime = config.get("runtime", _MISSING)
|
||||
if runtime is _MISSING:
|
||||
return DEFAULT_NOFILE_SOFT_LIMIT
|
||||
if not isinstance(runtime, Mapping):
|
||||
return None
|
||||
|
||||
raw_value = runtime.get("nofile_soft_limit", _MISSING)
|
||||
if raw_value is _MISSING:
|
||||
return DEFAULT_NOFILE_SOFT_LIMIT
|
||||
if raw_value is None or raw_value is False:
|
||||
return None
|
||||
if raw_value is True or not isinstance(raw_value, int):
|
||||
return None
|
||||
if raw_value <= 0:
|
||||
return None
|
||||
return raw_value
|
||||
|
||||
|
||||
def configured_nofile_soft_limit(
|
||||
config: Mapping[str, Any] | None = None,
|
||||
) -> int | None:
|
||||
"""Public accessor for the resolved ``runtime.nofile_soft_limit`` target.
|
||||
|
||||
Used by service-definition generators (e.g. the launchd plist) so the
|
||||
persisted service limits and the in-process floor share one config knob.
|
||||
Returns ``None`` when the adjustment is disabled or unresolvable.
|
||||
"""
|
||||
return _configured_nofile_soft_limit(config)
|
||||
|
||||
|
||||
def apply_nofile_soft_limit(
|
||||
config: Mapping[str, Any] | None = None,
|
||||
) -> bool:
|
||||
"""Raise this process's ``RLIMIT_NOFILE`` soft limit when possible.
|
||||
|
||||
The target defaults to :data:`DEFAULT_NOFILE_SOFT_LIMIT` and can be set with
|
||||
``runtime.nofile_soft_limit``. The target is clamped to a finite hard limit,
|
||||
never lowers an existing higher soft limit, and returns ``False`` for an
|
||||
explicit opt-out or when the platform/sandbox refuses the operation.
|
||||
|
||||
This is intentionally best-effort. Unsupported platforms, malformed
|
||||
settings, and denied ``setrlimit`` calls must never prevent a server from
|
||||
starting.
|
||||
"""
|
||||
if _resource is None:
|
||||
return False
|
||||
|
||||
target = _configured_nofile_soft_limit(config)
|
||||
if target is None:
|
||||
return False
|
||||
|
||||
try:
|
||||
nofile = _resource.RLIMIT_NOFILE
|
||||
current_soft, current_hard = _resource.getrlimit(nofile)
|
||||
# On platforms where RLIM_INFINITY is represented as -1, ordinary
|
||||
# integer ordering would make an unlimited soft limit look lower than
|
||||
# every positive target. Never replace infinity with a finite limit.
|
||||
if current_soft == getattr(_resource, "RLIM_INFINITY", object()):
|
||||
return False
|
||||
if current_soft >= target:
|
||||
return False
|
||||
|
||||
if current_hard == getattr(_resource, "RLIM_INFINITY", object()):
|
||||
new_soft = target
|
||||
else:
|
||||
new_soft = min(target, current_hard)
|
||||
if new_soft <= current_soft:
|
||||
return False
|
||||
|
||||
_resource.setrlimit(nofile, (new_soft, current_hard))
|
||||
return True
|
||||
except Exception:
|
||||
# This helper runs before server startup and must fail open for
|
||||
# unsupported/sandboxed environments and denied resource changes.
|
||||
logger.debug("Could not raise RLIMIT_NOFILE soft limit", exc_info=True)
|
||||
return False
|
||||
|
||||
|
||||
__all__ = [
|
||||
"DEFAULT_NOFILE_SOFT_LIMIT",
|
||||
"apply_nofile_soft_limit",
|
||||
"configured_nofile_soft_limit",
|
||||
]
|
||||
Reference in New Issue
Block a user