Skip to content

fix(gcs): retry transient uploads before crashing consumer - #371

Merged
enochtangg merged 4 commits into
mainfrom
filippopacifici/inc-2473-ensure-gcs-writer-failures-retry-without-committing-offsets
Sep 21, 2026
Merged

enochtangg merged 4 commits into
mainfrom
filippopacifici/inc-2473-ensure-gcs-writer-failures-retry-without-committing-offsets

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Transient GCS upload failures in gcs_writer were returned as RunTaskError::RetryableError. Arroyo logs that and drops the message, then later commits offsets past the failed parquet batch. That can permanently lose outcomes data.

It seems arroyo is not actually retrying retryable errors.
https://github.com/getsentry/arroyo/blob/main/rust-arroyo/src/processing/strategies/run_task_in_threads.rs#L194-L196
It seems the task that raises a Retryable error is just ignored.

This adds a retry_policy function that performs the retry when uploading fails for reasons that are not on the
client side. It applies exponential back off.


Fixes INC-2473.

Requested by Filippo Pacifici.

--

View Junior Session [Sentry]

Retry GCS writer token/request failures with exponential backoff.
Return RunTaskError::Other after max attempts or on HTTP 4xx so arroyo
crashes the consumer instead of discarding the batch and committing.

Co-Authored-By: Filippo Pacifici <fpacifici@sentry.io>
@linear-code

linear-code Bot commented Aug 25, 2026

Copy link
Copy Markdown

INC-2473

@fpacifici
fpacifici marked this pull request as ready for review September 17, 2026 17:29
@fpacifici
fpacifici requested a review from a team as a code owner September 17, 2026 17:29
Comment thread sentry_streams/src/gcs_writer.rs Outdated

@enochtangg enochtangg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just two small comments

Comment thread sentry_streams/src/gcs_writer.rs Outdated
assert!(StatusCode::UNAUTHORIZED.is_client_error());
assert!(StatusCode::FORBIDDEN.is_client_error());
assert!(StatusCode::NOT_FOUND.is_client_error());
assert!(StatusCode::TOO_MANY_REQUESTS.is_client_error());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A 429 is classified as permanent. Does that mean a GCS rate-limit stop the consumer rather than retrying? I think in this case, we'd want to retry with exponential backoff?

attempt
);
let gcs_labels = vec![("source".to_string(), route_source.to_string())];
metrics::histogram!(METRIC_SINK_GCS_WRITER_BYTES, &gcs_labels).record(bytes_len as f64);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also add a DD counter for retries and exhaustion?

@enochtangg
enochtangg merged commit 9fc9211 into main Sep 21, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant