fix: common mechanism for retries in insert, upsert and delete - #347
fix: common mechanism for retries in insert, upsert and delete#347konstantinoscs wants to merge 1 commit into
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
a0a35b9 to
d583fea
Compare
e576dea to
96e2b74
Compare
96e2b74 to
9b76e9b
Compare
| if not math.isfinite(retry_delay_seconds) or retry_delay_seconds < 0: | ||
| raise ValueError("retry_delay_seconds must be finite and >= 0") |
There was a problem hiding this comment.
I would suggest to give an upper bound (maybe 300 seconds / 5 minutes?), rather than only checking if the delay is finite.
There was a problem hiding this comment.
It's a bit confusing because the upper bound is anyway decided in retry_ceiling = min(retry_delay_seconds, _MAX_COMMIT_RETRY_DELAY_SECONDS) inside _commit_with-retry_().
I'll add some clarification in the documentation for this
There was a problem hiding this comment.
If it's handled somewhere else, I would just be consistent with the above line then - retry_delay_seconds < 0 is probably enough here.
| self, | ||
| operation: Callable[[], TRetryResult], | ||
| max_retries: int, | ||
| retry_delay_seconds: float, |
There was a problem hiding this comment.
I would suggest to use an int here, rather than float, unless there's a strong need for sub second delays.
There was a problem hiding this comment.
So the default value is itself a float (0.5). Also the randomized backoff produces fractional values.
I think float is the correct thing here
| return operation() | ||
| except CommitFailedException: | ||
| if attempt == max_retries: | ||
| raise |
There was a problem hiding this comment.
I would raise a new exception, like CommitRetryExhaustionException.
There was a problem hiding this comment.
This should remain CommitFailedException because it's actually the PyIceberg exception.
Preserving that exception:
- retains the original failure details;
- keeps existing except CommitFailedException handlers working;
- avoids introducing Tower-specific behavior for S3 Tables and BYO callers.
A new exception would be a breaking change unless it subclassed CommitFailedException, and even then it adds little value.
| if attempt == max_retries: | ||
| raise | ||
|
|
||
| delay = random.uniform(0.0, retry_ceiling) |
There was a problem hiding this comment.
Hmm. The way that this is used, compared to what the naming of the variable is, could be confusing (I was not sure why we have this jitter when we're using retry_delay_seconds). I'd suggest to rename retry_delay_seconds to max_retry_delay to make it clear it's the maximum, not the actual delay.
There was a problem hiding this comment.
Actually, max_retry_delay is also inaccurate: the supplied value is only the maximum for the first retry; later ceilings grow until the separate 30-second cap we discussed above.
The biggest problem though is that It is also an existing public keyword across insert, upsert, and delete, so renaming it breaks callers on every catalog type.
I’d keep retry_delay_seconds, improve its documentation, and use initial_retry_ceiling_seconds internally
3055dd3 to
8e793a7
Compare
8e793a7 to
26243f8
Compare
What this does
This PR makes table writes more resilient when two writers try to commit at the same time.
Insert, upsert, and delete now share one retry mechanism. After a genuine Iceberg commit conflict, the SDK waits for a small randomized delay, refreshes the table metadata, and tries again. The delay grows between attempts and is capped at 30 seconds.
Safety
Only a known
CommitFailedExceptionis retried. Authentication, permission, network, validation, not-found, and unknown-commit-state errors still fail immediately, because replaying those operations could duplicate or hide a write.This does not change catalog routing or credential vending, so S3 Tables and BYO behavior is preserved.
Testing
Tests cover all three write operations, retry timing and ordering, exhausted retries, refresh failures, and errors that must not be retried.