diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index 0b1f97046b84..edc2e008178d 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -3090,7 +3090,19 @@ def generate_launchd_plist() -> str: SuccessfulExit - + + SoftResourceLimits + + NumberOfFiles + 65536 + + + HardResourceLimits + + NumberOfFiles + 65536 + + StandardOutPath {log_dir}/gateway.log diff --git a/tests/hermes_cli/test_gateway_service.py b/tests/hermes_cli/test_gateway_service.py index c6baa7156324..da769e429e93 100644 --- a/tests/hermes_cli/test_gateway_service.py +++ b/tests/hermes_cli/test_gateway_service.py @@ -1629,6 +1629,20 @@ def test_launchd_plist_includes_profile(self, tmp_path, monkeypatch): assert "--profile" in plist assert "mybot" in plist + def test_launchd_plist_sets_nofiles_resource_limits(self, tmp_path, monkeypatch): + """generate_launchd_plist must set NumberOfFiles limits so the long-running + gateway doesn't hit launchd's default 256 soft RLIMIT_NOFILE (issue #36899).""" + profile_dir = tmp_path / ".hermes" + profile_dir.mkdir(parents=True) + monkeypatch.setattr(Path, "home", lambda: tmp_path) + monkeypatch.setenv("HERMES_HOME", str(profile_dir)) + monkeypatch.setattr(gateway_cli, "get_hermes_home", lambda: profile_dir) + plist = gateway_cli.generate_launchd_plist() + assert "SoftResourceLimits" in plist + assert "HardResourceLimits" in plist + assert plist.count("NumberOfFiles") == 2 + assert plist.count("65536") >= 2 + def test_launchd_plist_path_uses_real_user_home_not_profile_home(self, tmp_path, monkeypatch): profile_dir = tmp_path / ".hermes" / "profiles" / "orcha" profile_dir.mkdir(parents=True)