You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(load): retry append loads instead of running them at most once
`append` was excluded from retries on the grounds that it is not
idempotent: if the server commits the load but the response is lost, a
retry would re-append the same rows.
That is not how the API behaves. It keys a receipt on `upload_id`, and a
re-POST of the same id replays the committed result rather than applying
the load again. So the invariant that makes a retry safe is re-sending
the same upload, not the mode. `ManagedDatabaseClient` stages once, in
`upload_parquet`, outside the operation it retries, so that invariant
holds for every mode — and a test now pins it, since a refactor moving
the upload inside the retry would break it silently.
The exclusion cost availability. The destination serialises writes per
table and refuses rather than queues, so concurrent writers to one table
are answered `409 RESOURCE_LOCKED`. An append had no budget to wait that
out, whatever `max_retries` the caller had configured — the one shape
that most needs patience was the one shape that had none.
`HotdataClient.load_managed_table(file=...)` uploads inside the call and
so does not hold the invariant. It is unwrapped and unaffected.
Two supporting changes the above needs:
Classify a 409 by its `error.code` rather than by the status alone.
`CONFLICT` is terminal — the request cannot succeed as posted, so the
previous behaviour spent the whole budget reaching the same answer.
`RESOURCE_LOCKED` stays transient. A 409 carrying no error envelope is
classified exactly as before. `HotdataError` now carries `status_code`,
`code` and `retry_after_seconds`, because the message is flattened and
truncated for readability and so cannot serve as a discriminator.
Honour `Retry-After` and jitter the backoff. `Retry-After` is a floor on
the ramp, capped like the ramp so a mistaken header cannot park an
attempt for an hour; jitter of up to +50% is added on top and never
subtracted, so a stated `Retry-After` is not undercut. Writers that
collide on one table started together and would otherwise retry in
lockstep and collide again. This lengthens a 20-attempt budget from 285s
to roughly 316-405s.
0 commit comments