Control socket server running in arbiter process. The server runs an asyncio event loop in a background thread, accepting connections and dispatching commands to handlers. Fork safety is handled via os.register_at_fork() - the server automatically stops before fork and restart
| 67 | |
| 68 | |
| 69 | class ControlSocketServer: |
| 70 | """ |
| 71 | Control socket server running in arbiter process. |
| 72 | |
| 73 | The server runs an asyncio event loop in a background thread, |
| 74 | accepting connections and dispatching commands to handlers. |
| 75 | |
| 76 | Fork safety is handled via os.register_at_fork() - the server |
| 77 | automatically stops before fork and restarts after in the parent. |
| 78 | """ |
| 79 | |
| 80 | def __init__(self, arbiter, socket_path, socket_mode=0o600): |
| 81 | """ |
| 82 | Initialize control socket server. |
| 83 | |
| 84 | Args: |
| 85 | arbiter: The Gunicorn arbiter instance |
| 86 | socket_path: Path for the Unix socket |
| 87 | socket_mode: Permission mode for socket (default 0o600) |
| 88 | """ |
| 89 | self.arbiter = arbiter |
| 90 | self.socket_path = socket_path |
| 91 | self.socket_mode = socket_mode |
| 92 | |
| 93 | self.handlers = CommandHandlers(arbiter) |
| 94 | self._server = None |
| 95 | self._loop = None |
| 96 | self._thread = None |
| 97 | self._running = False |
| 98 | self._was_running_before_fork = False |
| 99 | |
| 100 | # Ensure fork handlers are registered |
| 101 | _register_fork_handlers() |
| 102 | |
| 103 | def start(self): |
| 104 | """Start server in background thread with asyncio event loop.""" |
| 105 | if self._running: |
| 106 | return |
| 107 | |
| 108 | self._running = True |
| 109 | self._thread = threading.Thread(target=self._run_loop, daemon=True) |
| 110 | self._thread.start() |
| 111 | |
| 112 | # Track this server for fork handling |
| 113 | _active_servers.add(self) |
| 114 | |
| 115 | def stop(self): |
| 116 | """Stop server and cleanup socket.""" |
| 117 | # Remove from active servers tracking |
| 118 | _active_servers.discard(self) |
| 119 | |
| 120 | if not self._running: |
| 121 | return |
| 122 | |
| 123 | self._running = False |
| 124 | |
| 125 | if self._loop and self._server: |
| 126 | # Schedule server close in the loop |
no outgoing calls