From 3ef3390fa731be2d1d81d2d566ccfdbb41562fe7 Mon Sep 17 00:00:00 2001 From: "seer-by-sentry[bot]" <157164994+seer-by-sentry[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 22:18:05 +0000 Subject: [PATCH 1/2] fix(supervisor): Ignore expected faults during process start/stop --- devservices/utils/supervisor.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/devservices/utils/supervisor.py b/devservices/utils/supervisor.py index 6403ed8..ed4f366 100644 --- a/devservices/utils/supervisor.py +++ b/devservices/utils/supervisor.py @@ -302,6 +302,10 @@ def start_process(self, name: str) -> None: try: self._get_rpc_client().supervisor.startProcess(name) except xmlrpc.client.Fault as e: + # Fault code 60 means ALREADY_STARTED, which is acceptable in concurrent scenarios + # where multiple threads may attempt to start the same process + if e.faultCode == 60: + return raise SupervisorProcessError( f"Failed to start process {name}: {e.faultString}" ) @@ -312,6 +316,10 @@ def stop_process(self, name: str) -> None: try: self._get_rpc_client().supervisor.stopProcess(name) except xmlrpc.client.Fault as e: + # Fault code 70 means NOT_RUNNING, which is acceptable in concurrent scenarios + # where multiple threads may attempt to stop the same process + if e.faultCode == 70: + return raise SupervisorProcessError( f"Failed to stop process {name}: {e.faultString}" ) From 654a3aae5a27fc3c190857c475471a122493a9e8 Mon Sep 17 00:00:00 2001 From: Hubert Deng Date: Wed, 17 Dec 2025 14:34:44 -0800 Subject: [PATCH 2/2] no magic numbers --- devservices/utils/supervisor.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/devservices/utils/supervisor.py b/devservices/utils/supervisor.py index ed4f366..fea9086 100644 --- a/devservices/utils/supervisor.py +++ b/devservices/utils/supervisor.py @@ -53,6 +53,17 @@ class SupervisorDaemonState(IntEnum): SHUTDOWN = -1 +class SupervisorFaultCode(IntEnum): + """ + Supervisor XML-RPC fault codes. + + https://supervisord.org/api.html#xml-rpc-api-documentation + """ + + ALREADY_STARTED = 60 + NOT_RUNNING = 70 + + class UnixSocketHTTPConnection(http.client.HTTPConnection): """HTTP connection over Unix sockets.""" @@ -302,9 +313,9 @@ def start_process(self, name: str) -> None: try: self._get_rpc_client().supervisor.startProcess(name) except xmlrpc.client.Fault as e: - # Fault code 60 means ALREADY_STARTED, which is acceptable in concurrent scenarios + # ALREADY_STARTED is acceptable in concurrent scenarios # where multiple threads may attempt to start the same process - if e.faultCode == 60: + if e.faultCode == SupervisorFaultCode.ALREADY_STARTED: return raise SupervisorProcessError( f"Failed to start process {name}: {e.faultString}" @@ -316,9 +327,9 @@ def stop_process(self, name: str) -> None: try: self._get_rpc_client().supervisor.stopProcess(name) except xmlrpc.client.Fault as e: - # Fault code 70 means NOT_RUNNING, which is acceptable in concurrent scenarios + # NOT_RUNNING is acceptable in concurrent scenarios # where multiple threads may attempt to stop the same process - if e.faultCode == 70: + if e.faultCode == SupervisorFaultCode.NOT_RUNNING: return raise SupervisorProcessError( f"Failed to stop process {name}: {e.faultString}"