diff --git a/scripts/gitea-actions/deploy-runner-config.xsh b/scripts/gitea-actions/deploy-runner-config.xsh index adda065..d637cd7 100755 --- a/scripts/gitea-actions/deploy-runner-config.xsh +++ b/scripts/gitea-actions/deploy-runner-config.xsh @@ -19,7 +19,9 @@ HOSTS = { } DEFAULT_MEM_FRACTION = 0.75 +DEFAULT_JOB_MEM_FRACTION = 0.9 MIN_RUNNER_MEM_MIB = 1024 +MIN_JOB_MEM_MIB = 128 def parse_mem_fraction(argv): @@ -35,6 +37,20 @@ def parse_mem_fraction(argv): raise SystemExit("--mem-fraction must be > 0 and <= 1") return fraction + +def parse_job_mem_fraction(argv): + fraction = DEFAULT_JOB_MEM_FRACTION + for arg in argv[1:]: + if arg.startswith("--job-mem-fraction="): + _, value = arg.split("=", 1) + try: + fraction = float(value) + except ValueError as exc: + raise SystemExit(f"Invalid --job-mem-fraction value: {value}") from exc + if fraction <= 0 or fraction > 1: + raise SystemExit("--job-mem-fraction must be > 0 and <= 1") + return fraction + def ssh(host, cmd): proc = subprocess.run( [ @@ -184,6 +200,25 @@ def upsert_service_deploy_memory(compose_text, service_names, value): return "\n".join(lines) + "\n" +def upsert_compose_env_var(compose_text, var_name, var_value, anchor_line): + lines = compose_text.splitlines() + new_line = f" - {var_name}={var_value}" + replaced = False + + for idx, line in enumerate(lines): + stripped = line.strip() + if stripped.startswith(f"- {var_name}="): + lines[idx] = new_line + replaced = True + + if not replaced: + for idx, line in enumerate(lines): + if line.strip() == anchor_line.strip(): + lines.insert(idx + 1, new_line) + + return "\n".join(lines) + "\n" + + def parse_mem_value_to_mib(raw_value): value = raw_value.strip().lower() if not value: @@ -258,7 +293,7 @@ def find_service_memory_value(compose_text, service_names): return None -def build_compose(compose_text, runner_mem_limit): +def build_compose(compose_text, runner_mem_limit, job_mem_limit): updated = compose_text volume_line = " - ./daemon.json:/etc/docker/daemon.json:ro" @@ -268,7 +303,15 @@ def build_compose(compose_text, runner_mem_limit): force_pull_line = " - GITEA_RUNNER_JOB_CONTAINER_FORCE_PULL=${GITEA_RUNNER_JOB_CONTAINER_FORCE_PULL:-false}" add_cfg_env = " - CONFIG_FILE=/config.yaml" - if add_cfg_env not in updated and force_pull_line in updated: + if force_pull_line in updated: + updated = upsert_compose_env_var(updated, "CONFIG_FILE", "/config.yaml", force_pull_line) + updated = upsert_compose_env_var( + updated, + "GITEA_RUNNER_JOB_CONTAINER_OPTIONS", + f"--memory={job_mem_limit} --memory-swap={job_mem_limit}", + force_pull_line, + ) + elif add_cfg_env not in updated: updated = updated.replace(force_pull_line, force_pull_line + "\n" + add_cfg_env) runner_services = {"act_runner_1", "act_runner_2", "runner1", "runner2"} @@ -321,8 +364,10 @@ def current_runner_baseline_mib(host, compose_text): mem_fraction = parse_mem_fraction(sys.argv) +job_mem_fraction = parse_job_mem_fraction(sys.argv) print(f"Runner mem fraction: {mem_fraction:.2f}") +print(f"Job mem fraction: {job_mem_fraction:.2f}") print("Fetching canonical runner config template") rc, template = ssh(TEMPLATE_HOST, f"cat {TEMPLATE_PATH}") if rc != 0 or not template.strip(): @@ -360,7 +405,15 @@ with tempfile.TemporaryDirectory() as tmpdir: print(f"runner_mem_baseline={baseline_source}") print(f"runner_mem_limit={runner_mem_limit} ({runner_mem_mib} MiB)") - new_compose = build_compose(compose, runner_mem_limit) + job_mem_mib = int(runner_mem_mib * job_mem_fraction) + if job_mem_mib < MIN_JOB_MEM_MIB: + job_mem_mib = MIN_JOB_MEM_MIB + if job_mem_mib >= runner_mem_mib and runner_mem_mib > 1: + job_mem_mib = runner_mem_mib - 1 + job_mem_limit = f"{job_mem_mib}m" + print(f"job_mem_limit={job_mem_limit} ({job_mem_mib} MiB)") + + new_compose = build_compose(compose, runner_mem_limit, job_mem_limit) rc, _ = ssh(host, f"mkdir -p {root}/backups") rc, _ = ssh(host, f"cp -f {root}/compose.yml {root}/backups/compose.yml.{now}") @@ -388,6 +441,8 @@ with tempfile.TemporaryDirectory() as tmpdir: print(out.strip()) rc, out = ssh(host, f"grep -n 'CONFIG_FILE=/config.yaml' {root}/compose.yml") print(out.strip()) + rc, out = ssh(host, f"grep -n 'GITEA_RUNNER_JOB_CONTAINER_OPTIONS=' {root}/compose.yml") + print(out.strip()) rc, out = ssh(host, f"grep -n 'memory:' {root}/compose.yml") print(out.strip())