Client for calling dirty workers from HTTP workers. Provides both sync and async APIs. The sync API is for traditional sync workers (sync, gthread), while the async API is for async workers (asgi, gevent).
| 29 | |
| 30 | |
| 31 | class DirtyClient: |
| 32 | """ |
| 33 | Client for calling dirty workers from HTTP workers. |
| 34 | |
| 35 | Provides both sync and async APIs. The sync API is for traditional |
| 36 | sync workers (sync, gthread), while the async API is for async |
| 37 | workers (asgi, gevent). |
| 38 | """ |
| 39 | |
| 40 | def __init__(self, socket_path, timeout=30.0): |
| 41 | """ |
| 42 | Initialize the dirty client. |
| 43 | |
| 44 | Args: |
| 45 | socket_path: Path to the dirty arbiter's Unix socket |
| 46 | timeout: Default timeout for operations in seconds |
| 47 | """ |
| 48 | self.socket_path = socket_path |
| 49 | self.timeout = timeout |
| 50 | self._sock = None |
| 51 | self._reader = None |
| 52 | self._writer = None |
| 53 | self._lock = threading.Lock() |
| 54 | |
| 55 | # ------------------------------------------------------------------------- |
| 56 | # Sync API (for sync HTTP workers) |
| 57 | # ------------------------------------------------------------------------- |
| 58 | |
| 59 | def connect(self): |
| 60 | """ |
| 61 | Establish sync socket connection to arbiter. |
| 62 | |
| 63 | Raises: |
| 64 | DirtyConnectionError: If connection fails |
| 65 | """ |
| 66 | if self._sock is not None: |
| 67 | return |
| 68 | |
| 69 | try: |
| 70 | self._sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
| 71 | self._sock.settimeout(self.timeout) |
| 72 | self._sock.connect(self.socket_path) |
| 73 | except (socket.error, OSError) as e: |
| 74 | self._sock = None |
| 75 | raise DirtyConnectionError( |
| 76 | f"Failed to connect to dirty arbiter: {e}", |
| 77 | socket_path=self.socket_path |
| 78 | ) from e |
| 79 | |
| 80 | def execute(self, app_path, action, *args, **kwargs): |
| 81 | """ |
| 82 | Execute an action on a dirty app (sync/blocking). |
| 83 | |
| 84 | Args: |
| 85 | app_path: Import path of the dirty app (e.g., 'myapp.ml:MLApp') |
| 86 | action: Action to call on the app |
| 87 | *args: Positional arguments |
| 88 | **kwargs: Keyword arguments |
no outgoing calls