Retry Policy¶
RetryPolicy provides unified retry configuration across backends.
Each backend maps the policy to its native retry mechanism, avoiding
retry multiplication.
Quick Start¶
from remote_store import RetryPolicy, Store
from remote_store.backends import SFTPBackend
# Custom retry: 5 attempts, 2s base backoff, 30s max, 0.5s jitter
policy = RetryPolicy(
max_attempts=5,
backoff_base=2.0,
backoff_max=30.0,
jitter=0.5,
)
backend = SFTPBackend(host="sftp.example.com", retry=policy)
store = Store(backend)
RetryPolicy Fields¶
| Field | Type | Default | Description |
|---|---|---|---|
max_attempts |
int |
3 |
Total attempts (including the initial one). Must be >= 1. |
backoff_base |
float |
1.0 |
Minimum delay in seconds between retries. |
backoff_max |
float |
60.0 |
Maximum delay in seconds between retries. |
jitter |
float |
1.0 |
Random jitter added to each delay (0 to jitter seconds). |
timeout |
float \| None |
None |
Overall timeout in seconds. None means no timeout. |
All fields are validated at construction time:
max_attempts >= 1backoff_base >= 0backoff_max >= 0jitter >= 0timeout > 0orNone
Disabling Retries¶
Use the disabled() factory to create a single-attempt (no retry) policy:
from remote_store import RetryPolicy
no_retry = RetryPolicy.disabled()
# Equivalent to: RetryPolicy(max_attempts=1)
TOML / YAML Configuration¶
Retry can be configured per-backend in config files:
[backends.production]
type = "sftp"
[backends.production.options]
host = "sftp.example.com"
[backends.production.retry]
max_attempts = 5
backoff_base = 2.0
backoff_max = 30.0
jitter = 0.5
backends:
production:
type: sftp
options:
host: sftp.example.com
retry:
max_attempts: 5
backoff_base: 2.0
backoff_max: 30.0
jitter: 0.5
Load with the standard config loaders:
from remote_store import RegistryConfig, Registry
config = RegistryConfig.from_toml("config.toml")
registry = Registry(config)
store = registry.get_store("my-store")
Per-Backend Mapping¶
Each backend translates RetryPolicy to its native retry mechanism.
Not all fields are mappable to every backend — unmappable fields are
logged at debug level.
SFTP¶
Full mapping via tenacity:
| RetryPolicy field | Tenacity equivalent |
|---|---|
max_attempts |
stop_after_attempt(N) |
backoff_base |
wait_exponential(min=N) |
backoff_max |
wait_exponential(max=N) |
jitter |
+ wait_random(0, N) |
timeout |
\| stop_after_delay(N) |
Retry scope: connection only (not per-operation).
S3¶
Only max_attempts is mappable to botocore:
backoff_base, backoff_max, jitter, and timeout are managed by
botocore internally and cannot be overridden.
S3-PyArrow¶
Dual mapping:
- PyArrow C++ side:
AwsStandardS3RetryStrategy(max_attempts=N) - s3fs side: Same botocore config as S3.
Only max_attempts is mappable on both sides.
Azure¶
Three fields are mappable to ExponentialRetry:
| RetryPolicy field | Azure equivalent |
|---|---|
max_attempts |
retry_total = max_attempts - 1 |
backoff_base |
initial_backoff = max(1, round(backoff_base)) |
jitter |
random_jitter_range = round(jitter) |
Azure expects integer seconds, so fractional values are rounded (with
a minimum of 1 for initial_backoff).
backoff_max and timeout are not mappable.
Local and Memory¶
These backends do not accept a retry parameter — passing one raises
TypeError. Local filesystem and in-memory operations do not have
transient failures that benefit from retry.
See also¶
- Retry policy example — runnable script
- Backend guides — per-backend configuration details