"""独立进程执行研究 Job —— 内存隔离的执行体(内存优化专项)。 由 job_executor._run_in_subprocess 以 `python -m app.cli.run_job ` 拉起 (cwd=backend/),入口先施加 RLIMIT_AS 上限再导入重依赖,随后执行与 API 内 execute_job 完全相同的状态机 / Experiment 归档逻辑。 环境变量: QLIB_JOB_MEM_LIMIT_GB —— 子进程虚拟地址空间上限(GB);父进程 spawn 时写入, 手动直接运行本命令而未设置时回退到 Settings(config job.max_memory_gb)。 """ from __future__ import annotations import os import sys def _apply_memory_limit() -> None: """尝试施加 RLIMIT_AS:达到上限时分配抛 MemoryError → Job 归档 failed, 而不是让内核 OOM 杀掉整机(8G Pi5 上保护同机其它服务)。 不按平台硬门禁:RLIMIT_AS 在 Linux / macOS 上都能设置,但**限额必须高于进程 当前的虚拟地址空间基线**,否则内核返回 EINVAL(CPython 表现为 `ValueError: current limit exceeds maximum limit`)。macOS 上 Python 进程的 地址空间基线可达数十 GB(共享缓存 + malloc 区预留),故 `job.max_memory_gb: 6` 在这类机器上会失败 —— 这是**配置阈值问题,不是平台不支持**,不应掩盖。 设置失败不阻断 Job,但如实打印原因与后果(AGENT.md §24「未实现项须如实标注」)。 """ try: gb = int(os.environ.get("QLIB_JOB_MEM_LIMIT_GB") or "") except (TypeError, ValueError): from app.core.config import get_settings gb = get_settings().job_memory_limit_gb limit = gb * 1024**3 import resource try: resource.setrlimit(resource.RLIMIT_AS, (limit, limit)) except (ValueError, OSError) as exc: print( f"[run_job] 内存上限 {gb}GB 设置失败({type(exc).__name__}: {exc});" "本 Job 无内存隔离保护。若限额低于进程虚拟地址空间基线(macOS 常见)," "可调大 config.yaml job.max_memory_gb 后重试。", file=sys.stderr, ) def main(argv: list[str] | None = None) -> int: args = list(sys.argv[1:] if argv is None else argv) if len(args) < 1: print("用法: python -m app.cli.run_job ", file=sys.stderr) return 2 _apply_memory_limit() # 先设内存上限再导入重依赖(pandas / sqlalchemy 等) from app.application.services.job_executor import default_factories, execute_job execute_job(args[0], **default_factories()) return 0 if __name__ == "__main__": raise SystemExit(main())