From be27ed4036de78f2b22de9b94b80151d8ec02eff Mon Sep 17 00:00:00 2001 From: Benoit Chesneau Date: Fri, 13 Feb 2026 01:56:39 +0100 Subject: [PATCH] fix(ctl): properly encode/decode MSG_TYPE_STATUS for dirty worker query - Add encode_status method to BinaryProtocol - Use arbiter.dirty_arbiter.socket_path instead of env var when available --- gunicorn/ctl/handlers.py | 14 +++++++++++--- gunicorn/dirty/protocol.py | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/gunicorn/ctl/handlers.py b/gunicorn/ctl/handlers.py index dedf349f..690c9842 100644 --- a/gunicorn/ctl/handlers.py +++ b/gunicorn/ctl/handlers.py @@ -474,7 +474,13 @@ class CommandHandlers: List of dirty worker info dicts, or empty list on error """ import socket - dirty_socket_path = os.environ.get('GUNICORN_DIRTY_SOCKET') + + # Get socket path from arbiter object or environment + dirty_socket_path = None + if hasattr(self.arbiter, 'dirty_arbiter') and self.arbiter.dirty_arbiter: + dirty_socket_path = getattr(self.arbiter.dirty_arbiter, 'socket_path', None) + if not dirty_socket_path: + dirty_socket_path = os.environ.get('GUNICORN_DIRTY_SOCKET') if not dirty_socket_path: return [] @@ -500,8 +506,10 @@ class CommandHandlers: data = response.get("data", {}) return data.get("workers", []) - except Exception: - pass + except Exception as e: + # Log error for debugging + if hasattr(self.arbiter, 'log') and self.arbiter.log: + self.arbiter.log.debug("Failed to query dirty workers: %s", e) return [] diff --git a/gunicorn/dirty/protocol.py b/gunicorn/dirty/protocol.py index b6e996af..8091b23f 100644 --- a/gunicorn/dirty/protocol.py +++ b/gunicorn/dirty/protocol.py @@ -277,6 +277,21 @@ class BinaryProtocol: header = BinaryProtocol.encode_header(MSG_TYPE_END, request_id, 0) return header + @staticmethod + def encode_status(request_id: int) -> bytes: + """ + Encode a status query message. + + Args: + request_id: Request identifier + + Returns: + bytes: Complete message (header + empty payload) + """ + # Status query has empty payload + header = BinaryProtocol.encode_header(MSG_TYPE_STATUS, request_id, 0) + return header + @staticmethod def encode_stash(request_id: int, op: int, table: str, key=None, value=None, pattern=None) -> bytes: @@ -586,6 +601,8 @@ class BinaryProtocol: message.get("value"), message.get("pattern") ) + elif msg_type == MSG_TYPE_STATUS: + return BinaryProtocol.encode_status(request_id) else: raise DirtyProtocolError(f"Unhandled message type: {msg_type}")