Raise Docker open file limit at startup

Raise the runtime container soft nofile limit before supervisord starts so WebUI and managed services inherit a larger descriptor allowance.

Add an explicit compose nofile example, document the startup contract, and cover the limit raise and hard-limit cap with focused regression tests.
This commit is contained in:
Alessandro 2026-06-24 11:00:00 +02:00
parent 1d90c27f3b
commit 68c31b51e1
4 changed files with 107 additions and 0 deletions

View file

@ -21,6 +21,7 @@
- Keep the two-runtime Python model aligned with the root contract.
- Do not bake secrets, local `.env` values, or user data into the image.
- Runtime startup must ensure `/a0/usr/uploads` exists before supervised services start.
- Runtime startup raises the soft open-file limit toward `A0_NOFILE_LIMIT` (default `65535`) before supervisord starts, bounded by the container hard limit.
## Work Guidance

View file

@ -6,5 +6,9 @@ services:
- ./agent-zero:/a0
ports:
- "50080:80"
ulimits:
nofile:
soft: 65535
hard: 65535
extra_hosts:
- "host.docker.internal:host-gateway"

View file

@ -9,6 +9,43 @@ if [ -z "$1" ]; then
fi
BRANCH="$1"
raise_open_file_limit() {
local requested="${A0_NOFILE_LIMIT:-65535}"
local soft
local hard
local target
if ! [[ "$requested" =~ ^[0-9]+$ ]] || [ "$requested" -lt 1 ]; then
echo "Warning: invalid A0_NOFILE_LIMIT='$requested'; keeping open file limit at $(ulimit -S -n)." >&2
return
fi
soft="$(ulimit -S -n)"
hard="$(ulimit -H -n)"
if [ "$soft" = "unlimited" ]; then
echo "Open file limit is already unlimited."
return
fi
target="$requested"
if [ "$hard" != "unlimited" ] && [ "$target" -gt "$hard" ]; then
target="$hard"
fi
if [ "$target" -gt "$soft" ]; then
if ulimit -S -n "$target"; then
echo "Raised open file soft limit from $soft to $(ulimit -S -n) (hard: $hard)."
else
echo "Warning: failed to raise open file soft limit from $soft to $target (hard: $hard)." >&2
fi
else
echo "Open file soft limit is $soft (target: $requested, hard: $hard)."
fi
}
raise_open_file_limit
# Copy all contents from persistent /per to root directory (/) without overwriting
cp -r --no-preserve=ownership,mode /per/* /

View file

@ -0,0 +1,65 @@
import re
import resource
import subprocess
from pathlib import Path
import pytest
REPO_ROOT = Path(__file__).resolve().parents[1]
INITIALIZE_SCRIPT = REPO_ROOT / "docker" / "run" / "fs" / "exe" / "initialize.sh"
def _raise_limit_function() -> str:
text = INITIALIZE_SCRIPT.read_text(encoding="utf-8")
match = re.search(r"^raise_open_file_limit\(\) \{\n.*?^\}\n", text, re.M | re.S)
assert match, "initialize.sh must define raise_open_file_limit"
return match.group(0)
def _run_bash(script: str) -> subprocess.CompletedProcess[str]:
return subprocess.run(
["bash", "-c", script],
check=True,
text=True,
capture_output=True,
)
def test_initialize_raises_soft_open_file_limit_to_requested_target():
function = _raise_limit_function()
result = _run_bash(
f"""
set -euo pipefail
{function}
ulimit -S -n 1024
A0_NOFILE_LIMIT=4096
raise_open_file_limit
test "$(ulimit -S -n)" = "4096"
"""
)
assert "Raised open file soft limit from 1024 to 4096" in result.stdout
def test_initialize_caps_open_file_limit_at_hard_limit():
_soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
if hard != resource.RLIM_INFINITY and hard < 2048:
pytest.skip("host hard open-file limit is too low for this regression test")
function = _raise_limit_function()
result = _run_bash(
f"""
set -euo pipefail
{function}
ulimit -S -n 1024
ulimit -H -n 2048
A0_NOFILE_LIMIT=65535
raise_open_file_limit
test "$(ulimit -S -n)" = "2048"
"""
)
assert "Raised open file soft limit from 1024 to 2048" in result.stdout