Source code for exlab_wizard.sync.transports
"""Sync transports package. Backend Spec §7.1.3.
Each transport is a thin async wrapper around an upstream binary. They
share a small common shape (``TransportResult``, ``TransportErrorKind``)
so the queue worker can treat outcomes uniformly while logging the raw
stdout/stderr for diagnostics.
"""
from __future__ import annotations
from dataclasses import dataclass
from enum import StrEnum
__all__ = [
"TransportError",
"TransportErrorKind",
"TransportResult",
]
[docs]
class TransportErrorKind(StrEnum):
"""Kind of failure that the queue worker uses to drive the retry policy.
Backend Spec §7.1.5.
- ``NETWORK``: timeout, ECONNRESET, transient SSH failure -- retried with
exponential backoff up to ``MAX_ATTEMPTS``.
- ``AUTH``: authentication failure -- terminal FAILED, no retry.
- ``HASH_MISMATCH``: post-transport hash check failed -- single retry of
the transport phase, then terminal.
- ``LOCAL_FILE_VANISHED``: the local file disappeared between transport
and verify -- terminal FAILED with ``local_file_vanished`` reason.
- ``UNKNOWN``: catch-all for transports returning a non-zero code we
don't recognize -- treated as ``NETWORK`` for retry purposes.
"""
NETWORK = "network"
AUTH = "auth"
HASH_MISMATCH = "hash_mismatch"
LOCAL_FILE_VANISHED = "local_file_vanished"
UNKNOWN = "unknown"
[docs]
@dataclass(frozen=True, slots=True)
class TransportResult:
"""Outcome of a transport push.
``ok`` is True iff the transport reported success. On failure,
``error_kind`` selects the retry path; ``stderr`` is the raw stderr
text for log surfacing; ``returncode`` is the subprocess exit code.
"""
ok: bool
error_kind: TransportErrorKind | None = None
stderr: str = ""
stdout: str = ""
returncode: int = 0
[docs]
class TransportError(Exception):
"""Raised when a transport probe cannot complete.
Distinct from :class:`TransportResult`: this surfaces conditions
where the transport's hashsum-style probe could not produce a
manifest at all -- either because the upstream binary is missing
(``error_kind=None`` for the historical "binary not on PATH" case)
or because the probe ran and failed in a classifiable way (AUTH,
NETWORK, UNKNOWN). The queue worker uses ``error_kind`` to route the
failure through the §7.1.5 retry policy:
- ``AUTH`` -- terminal FAILED, no retry (configuration problem).
- ``NETWORK`` -- non-terminal failure, exponential backoff retry.
- ``UNKNOWN`` -- treated as ``NETWORK`` for retry purposes.
- ``None`` -- legacy "binary missing" callers. Routed through the
§7.1.5 HASH_MISMATCH branch: one immediate retry, then terminal
FAILED on the second occurrence. The operator surfaces the
binary-missing reason via ``last_error``.
"""
def __init__(
self,
message: str,
*,
error_kind: TransportErrorKind | None = None,
) -> None:
super().__init__(message)
self.error_kind = error_kind