yggdrasil.path._retry¶
_retry ¶
Generic retry wrapper for remote-path SDK calls.
Only transient backend errors (InternalError, BadRequest, 500/503, socket timeouts) are retried — up to 4 times with a flat 1 s sleep between attempts.
Permission errors (PermissionDenied / 401 / 403, expired tokens, …)
fail fast: they're deterministic from the caller's point of view
— the principal genuinely lacks the grant, the token is dead, or the
auth config is wrong. Sleeping and retrying just hides the real
problem; the caller (or a higher-level recovery path like the
credential-vending auto-grant in :mod:yggdrasil.databricks.aws)
decides what to do.
Anything else (NotFound, AlreadyExists, FileNotFoundError, ValueError, …) is not retried either — those are deterministic.
This module deliberately avoids importing the boto / databricks SDK
exception classes; it duck-types on the exception's class name and
the optional response attribute that boto-style errors carry.
That keeps the retry layer usable with mocks in tests.
is_transient ¶
True when exc should be retried as a transient backend error.
is_permission ¶
True when exc looks like an auth / permission failure.
retry_sdk_call ¶
retry_sdk_call(
func: Callable[..., _T],
*args: Any,
max_transient_retries: int = 4,
base_sleep: float = 1.0,
sleep: Callable[[float], None] = time.sleep,
**kwargs: Any
) -> _T
Call func(args, *kwargs) with the Databricks/AWS retry policy.
Sleeps a flat base_sleep seconds between transient retries (no
exponential backoff — transient SDK errors recover fast on a
healthy backend, and a long ceiling just stalls the caller).
Permission errors fail fast — they're deterministic from the
SDK's perspective and any recovery (self-grant, owner takeover,
…) belongs in a higher-level handler.
The sleep callable is injected so tests can pass a no-op or a
spy. The default is :func:time.sleep.
Non-transient errors propagate immediately — that includes
:class:PermissionDenied, :class:FileNotFoundError,
:class:ValueError, :class:KeyError, and any custom error
type the caller wants to surface deterministically.