fix(runners): size limits from host memory share
All checks were successful
CICD Start / Sanity and Base Decision (pull_request) Successful in 15s
CICD Start / Sanity and Base Decision (push) Successful in 30s

This commit is contained in:
copilotcoder
2026-07-05 13:23:34 -04:00
parent 9ae4d6eafb
commit 2eb94d18f3

View File

@@ -20,6 +20,7 @@ HOSTS = {
DEFAULT_MEM_FRACTION = 0.75
DEFAULT_JOB_MEM_FRACTION = 0.9
DEFAULT_HOST_MEM_SHARE = 0.25
MIN_RUNNER_MEM_MIB = 1024
MIN_JOB_MEM_MIB = 128
@@ -51,6 +52,20 @@ def parse_job_mem_fraction(argv):
raise SystemExit("--job-mem-fraction must be > 0 and <= 1")
return fraction
def parse_host_mem_share(argv):
share = DEFAULT_HOST_MEM_SHARE
for arg in argv[1:]:
if arg.startswith("--host-mem-share="):
_, value = arg.split("=", 1)
try:
share = float(value)
except ValueError as exc:
raise SystemExit(f"Invalid --host-mem-share value: {value}") from exc
if share <= 0 or share > 1:
raise SystemExit("--host-mem-share must be > 0 and <= 1")
return share
def ssh(host, cmd):
proc = subprocess.run(
[
@@ -328,44 +343,24 @@ def host_total_mem_mib(host):
return int(int(mem_kib.strip()) / 1024.0)
def host_mem_limit(host, fraction):
def host_mem_limit(host, host_mem_share, fraction):
total_mib = host_total_mem_mib(host)
target_mib = int(total_mib * fraction)
host_share_mib = int(total_mib * host_mem_share)
target_mib = int(host_share_mib * fraction)
if target_mib < MIN_RUNNER_MEM_MIB:
target_mib = MIN_RUNNER_MEM_MIB
return f"{target_mib}m", target_mib, f"host-total({total_mib}MiB)"
def current_runner_baseline_mib(host, compose_text):
deploy_memory_value = find_service_memory_value(
compose_text,
{"act_runner_1", "act_runner_2", "runner1", "runner2"},
return (
f"{target_mib}m",
target_mib,
f"host-total({total_mib}MiB) * host-share({host_mem_share:.2f}) -> {host_share_mib}MiB * mem-fraction({fraction:.2f})",
)
deploy_mib = parse_mem_value_to_mib(deploy_memory_value) if deploy_memory_value else None
if deploy_mib and deploy_mib > 0:
return deploy_mib, f"compose(deploy.memory={deploy_memory_value})"
compose_value = find_service_key_value(
compose_text,
{"act_runner_1", "act_runner_2", "runner1", "runner2"},
"mem_limit",
)
compose_mib = parse_mem_value_to_mib(compose_value) if compose_value else None
if compose_mib and compose_mib > 0:
return compose_mib, f"compose(mem_limit={compose_value})"
rc, inspect_mem = ssh(host, "docker inspect gitea-act-runner-1 --format '{{.HostConfig.Memory}}'")
if rc == 0:
inspect_mib = parse_mem_value_to_mib(inspect_mem)
if inspect_mib and inspect_mib > 0:
return inspect_mib, f"inspect(HostConfig.Memory={inspect_mem.strip()})"
return None, "none"
mem_fraction = parse_mem_fraction(sys.argv)
job_mem_fraction = parse_job_mem_fraction(sys.argv)
host_mem_share = parse_host_mem_share(sys.argv)
print(f"Host mem share: {host_mem_share:.2f}")
print(f"Runner mem fraction: {mem_fraction:.2f}")
print(f"Job mem fraction: {job_mem_fraction:.2f}")
print("Fetching canonical runner config template")
@@ -389,18 +384,15 @@ with tempfile.TemporaryDirectory() as tmpdir:
print("Could not read compose.yml")
continue
baseline_mib, baseline_source = current_runner_baseline_mib(host, compose)
if baseline_mib is None:
try:
runner_mem_limit, runner_mem_mib, baseline_source = host_mem_limit(host, mem_fraction)
except RuntimeError as exc:
print(str(exc))
continue
else:
runner_mem_mib = int(baseline_mib * mem_fraction)
if runner_mem_mib < 1:
runner_mem_mib = 1
runner_mem_limit = f"{runner_mem_mib}m"
try:
runner_mem_limit, runner_mem_mib, baseline_source = host_mem_limit(
host,
host_mem_share,
mem_fraction,
)
except RuntimeError as exc:
print(str(exc))
continue
print(f"runner_mem_baseline={baseline_source}")
print(f"runner_mem_limit={runner_mem_limit} ({runner_mem_mib} MiB)")