E2E8 fix(inkless:storage): bound bulk-delete failure logging [KC-430] by jeqo · Pull Request #742 · aiven/inkless · GitHub
[go: up one dir, main page]

Skip to content
< 8000 div id="docked-side-panel-content" class="height-full d-flex flex-column">

fix(inkless:storage): bound bulk-delete failure logging [KC-430] - #742

Merged
jeqo merged 1 commit into
mainfrom
jeqo/bound-bulk-delete-logging
Aug 19, 2026
Merged

jeqo merged 1 commit into
mainfrom
jeqo/bound-bulk-delete-logging

Conversation

@jeqo
@jeqo jeqo commented Aug 11, 2026 •
Copy link
Copy Markdown
Contributor

A delete pass that fails for every key it submitted logs one line per key, with a stack trace each on Azure, and repeats that on every cleanup cycle, since undeleted keys stay marked for deletion. GCS interpolates the whole key set into the exception message, which is the bug #733 fixed for S3.

Count the failures of a pass by error code and log them once, at INFO when every code is a throttle and at WARN otherwise, so the output is bounded by the distinct codes rather than by the worklist. Report an exception that carries no service code in full instead, since the stack trace is then the only diagnosis: a whole-request SdkException on S3, any non-BlobStorageException on Azure. Both stop the pass, because neither is attributable to a single key and the rest retry on the next cycle. GCS logs only the key count, since it can't report per-key results.

The counts describe one pass and never the worklist: FileCleaner reports how many candidates it deleted and derives FileCleanerFilesFailedRate from the same numbers.

Both throttle sets keep only the codes the provider calls throttling, since the set picks the log level and a transient server error doesn't self-heal like backpressure. S3 drops ServiceUnavailable, which AWS classifies as a retryable 503. Azure keeps ServerBusy alone, sourced from BlobErrorCode.

KC-430

@jeqo
jeqo force-pushed the jeqo/file-delete branch from 894fa9c to e2b57cf Compare August 12, 2026 16:06
@jeqo
jeqo force-pushed the jeqo/bound-bulk-delete-logging branch from ffcad22 to 194bab8 Compare August 12, 2026 16:11
@jeqo
jeqo requested a balanced review from Copilot August 12, 2026 16:14
Copilot AI 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.

Pull request overview

Bounds repeated bulk-delete failure logs across cloud storage backends.

Changes:

  • Adds aggregated error counts, samples, and causes.
  • Applies bounded logging to S3 and Azure.
  • Removes GCS key enumeration from exceptions.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
DeleteErrorSummaryTest.java Tests summary bounds and formatting.
DeleteErrorSummary.java Implements aggregated failure logging.
S3Storage.java Aggregates per-key S3 failures.
AzureBlobStorage.java Aggregates Azure delete exceptions.
GcsStorage.java Reports only failed key count.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Base automatically changed from jeqo/file-delete to main August 13, 2026 09:48
@jeqo
jeqo force-pushed the jeqo/bound-bulk-delete-logging branch from 194bab8 to c8434f7 Compare August 18, 2026 16:24
@jeqo
jeqo requested a balanced review from Copilot August 18, 2026 16:25
Copilot AI 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.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (1)

storage/inkless/src/test/java/io/aiven/inkless/storage_backend/common/DeleteErrorSummaryTest.java:32

  • AGENTS.md requires spelling out “for example” instead of using e.g. in comments. Replace the abbreviation in this new Javadoc.
 * A delete pass can fail for every key it submitted (e.g. a bucket policy denial) and repeats every

@jeqo
jeqo force-pushed the jeqo/bound-bulk-delete-logging branch from c8434f7 to e1dd358 Compare August 18, 2026 16:45
A delete pass that fails for every key it submitted logs one line per key, with a
stack trace each on Azure, and repeats that on every cleanup cycle, since undeleted
keys stay marked for deletion. GCS interpolates the whole key set into the exception
message, which is the bug #733 fixed for S3.

Count the failures of a pass by error code and log them once, at INFO when every code
is a throttle and at WARN otherwise, so the output is bounded by the distinct codes
rather than by the worklist. Report an exception that carries no service code in full
instead, since the stack trace is then the only diagnosis: a whole-request
`SdkException` on S3, any non-`BlobStorageException` on Azure. Both stop the pass,
because neither is attributable to a single key and the rest retry on the next cycle.
GCS logs only the key count, since it can't report per-key results.

The counts describe one pass and never the worklist: `FileCleaner` reports how many
candidates it deleted and derives `FileCleanerFilesFailedRate` from the same numbers.

Both throttle sets keep only the codes the provider calls throttling, since the set
picks the log level and a transient server error doesn't self-heal like backpressure.
S3 drops `ServiceUnavailable`, which AWS classifies as a retryable 503. Azure keeps
`ServerBusy` alone, sourced from `BlobErrorCode`.

[KC-430]

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jeqo
jeqo force-pushed the jeqo/bound-bulk-delete-logging branch from e1dd358 to b7ec806 Compare August 18, 2026 21:42
@jeqo jeqo changed the title fix(inkless:storage): bound bulk-delete failure logging fix(inkless:storage): bound bulk-delete failure logging [KC-430] Aug 18, 2026
@jeqo
jeqo requested a balanced review from Copilot August 18, 2026 21:54
Copilot AI 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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (4)

storage/inkless/src/main/java/io/aiven/inkless/storage_backend/azure/AzureBlobStorage.java:231

  • This new early exit contradicts the method comment at lines 212–215, which says that a failure on one key must not abandon the remaining keys. Update that comment to distinguish coded service failures, which continue, from code-less or unexpected failures, which stop the pass.
                LOGGER.warn("Deleting {} failed unexpectedly, stopping the pass", key, Exceptions.unwrap(e));
                break;

storage/inkless/src/main/java/io/aiven/inkless/storage_backend/azure/AzureBlobStorage.java:241

  • No Azure failure-path test exercises this new aggregation and level selection; the shared backend tests cover only successful bulk deletion. Add tests that verify one aggregate INFO record for ServerBusy, one aggregate WARN record for a non-throttle code, and the early-stop behavior for an unexpected exception.
        if (!failuresByCode.isEmpty()) {
            // Throttling is backpressure the next FileCleaner cycle retries; any other code needs an
            // operator, so it must not sit at INFO while the worklist stops draining.
            if (THROTTLE_ERROR_CODES.containsAll(failuresByCode.keySet())) {
                LOGGER.info("Delete failures by error code {}", failuresByCode);
            } else {
                LOGGER.warn("Delete failures by error code {}", failuresByCode);

storage/inkless/src/main/java/io/aiven/inkless/storage_backend/azure/AzureBlobStorage.java:225

  • BlobStorageException#getErrorCode() can return null when Azure or an intermediary returns no service error code. String.valueOf turns that into the literal "null", so this path logs only {null=n} and drops the stack trace that is needed to diagnose a code-less response. Detect a missing code, log the exception in full, and stop the pass; aggregate only real service codes.

This issue also appears in the following locations of the same file:

  • line 230
  • line 235
                failuresByCode.merge(String.valueOf(e.getErrorCode()), 1, Integer::sum);

storage/inkless/src/main/java/io/aiven/inkless/storage_backend/s3/S3Storage.java:215

  • The existing S3StorageDeleteTest exercises mixed delete errors but asserts only returned keys and request count. It doesn't verify this PR's main contract: one bounded aggregate log at INFO when all codes are throttles and at WARN otherwise. Add log-capture cases for all-throttle and mixed-code responses so level or per-key logging regressions fail tests.
            if (THROTTLE_ERROR_CODES.containsAll(failuresByCode.keySet())) {
                LOGGER.info("Delete failures by error code {}", failuresByCode);
            } else {
                LOGGER.warn("Delete failures by error code {}", failuresByCode);

@jeqo
jeqo marked this pull request as ready for review August 18, 2026 22:03
@jeqo
jeqo requested a review from tvainika August 18, 2026 22:03
@jeqo
jeqo merged commit 7efa85f into main Aug 19, 2026
11 checks passed
@jeqo
jeqo deleted the jeqo/bound-bulk-delete-logging branch August 19, 2026 06:13
jeqo added a commit that referenced this pull request Aug 19, 2026
A delete pass that fails for every key it submitted logs one line per key, with a
stack trace each on Azure, and repeats that on every cleanup cycle, since undeleted
keys stay marked for deletion. GCS interpolates the whole key set into the exception
message, which is the bug #733 fixed for S3.

Count the failures of a pass by error code and log them once, at INFO when every code
is a throttle and at WARN otherwise, so the output is bounded by the distinct codes
rather than by the worklist. Report an exception that carries no service code in full
instead, since the stack trace is then the only diagnosis: a whole-request
`SdkException` on S3, any non-`BlobStorageException` on Azure. Both stop the pass,
because neither is attributable to a single key and the rest retry on the next cycle.
GCS logs only the key count, since it can't report per-key results.

The counts describe one pass and never the worklist: `FileCleaner` reports how many
candidates it deleted and derives `FileCleanerFilesFailedRate` from the same numbers.

Both throttle sets keep only the codes the provider calls throttling, since the set
picks the log level and a transient server error doesn't self-heal like backpressure.
S3 drops `ServiceUnavailable`, which AWS classifies as a retryable 503. Azure keeps
`ServerBusy` alone, sourced from `BlobErrorCode`.

[KC-430]

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
jeqo added a commit that referenced this pull request Aug 19, 2026
A delete pass that fails for every key it submitted logs one line per key, with a
stack trace each on Azure, and repeats that on every cleanup cycle, since undeleted
keys stay marked for deletion. GCS interpolates the whole key set into the exception
message, which is the bug #733 fixed for S3.

Count the failures of a pass by error code and log them once, at INFO when every code
is a throttle and at WARN otherwise, so the output is bounded by the distinct codes
rather than by the worklist. Report an exception that carries no service code in full
instead, since the stack trace is then the only diagnosis: a whole-request
`SdkException` on S3, any non-`BlobStorageException` on Azure. Both stop the pass,
because neither is attributable to a single key and the rest retry on the next cycle.
GCS logs only the key count, since it can't report per-key results.

The counts describe one pass and never the worklist: `FileCleaner` reports how many
candidates it deleted and derives `FileCleanerFilesFailedRate` from the same numbers.

Both throttle sets keep only the codes the provider calls throttling, since the set
picks the log level and a transient server error doesn't self-heal like backpressure.
S3 drops `ServiceUnavailable`, which AWS classifies as a retryable 503. Azure keeps
`ServerBusy` alone, sourced from `BlobErrorCode`.

[KC-430]

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

3 participants

0