Skip to content

fix: skip attachment resource cleanup when its policy is gone - #10294

Open
ryanchou1994 wants to merge 1 commit into
halo-dev:mainfrom
ryanchou1994:fix/attachment-policy-delete-404
Open

ryanchou1994 wants to merge 1 commit into
halo-dev:mainfrom
ryanchou1994:fix/attachment-policy-delete-404

Conversation

@ryanchou1994

Copy link
Copy Markdown

What type of PR is this?

  • Feature
  • Bug fix
  • Improvement
  • Cleanup
  • Documentation

What this PR does / why we need it:

When a storage policy is deleted while attachments still reference it, those attachments can no longer be deleted and the log fills up with 404 errors.

AttachmentReconciler#cleanUpResources calls attachmentService.delete(attachment), whose first step is client.get(Policy.class, ...). With the policy gone that errors with ExtensionNotFoundException (404). The reconciler does not handle it, so DefaultController logs "aborted with an error, re-enqueuing" and requeues unconditionally, forever, because the missing policy never comes back. The finalizer is never removed either, so the attachment record stays as well.

A missing policy or config map is a permanent state, not a transient failure: no handler can resolve the attachment any more, so there is nothing left to clean up. This treats that case as "nothing to do" - log a warning and let the reconciler remove the finalizer, so the attachment record can finally be deleted as the user asked.

Tests: a new AttachmentReconcilerTest with three cases - policy missing (finalizer removed, no exception), normal cleanup (unchanged), and any other error still propagating so the finalizer is kept and the request is retried. The first one fails on current main.

Which issue(s) this PR fixes:

Fixes #6380

Special notes for your reviewer:

  • The fix sits in the reconciler rather than in DefaultAttachmentService#delete, so the public AttachmentService contract that plugins depend on is unchanged.
  • onErrorResume is scoped to ExtensionNotFoundException. If a plugin handler's own delete() throws that exception for some unrelated extension, it would also be treated as "nothing to clean up". Narrowing further would mean pre-checking the policy and its config map in the reconciler, duplicating what the service already does. Happy to switch if you prefer that shape.
  • This follows the direction you took in 当对象存储桶被删除时S3存储的附件无法删除 #7310, where a missing upstream file should be ignored rather than retried.
  • Remote files that were already unreachable are still not removed; the attachment record goes away and the warning names both the attachment and the missing extension, so the leftover can be found later.
  • I decided to submit this fix and reviewed it before sending; the implementation and the tests were written with AI assistance. Verification: the three unit tests above are red before and green after on Linux with JDK 21, and spotlessJavaCheck is clean. Not covered: I did not reproduce the original 404 loop end to end against a live deployment.

Does this PR introduce a user-facing change?

修复删除存储策略后,其关联附件无法删除且后台日志持续输出 404 错误的问题

Deleting a storage policy that attachments still reference leaves those attachments undeletable and floods the log with 404 errors.

AttachmentReconciler#cleanUpResources calls attachmentService.delete(attachment), whose first step is client.get(Policy.class, ...). With the policy gone that errors with ExtensionNotFoundException, which the reconciler does not handle, so DefaultController requeues the request unconditionally and forever. The finalizer is never removed either, so the attachment record stays too.

A missing policy or config map is permanent, not transient: no handler can resolve the attachment any more, so there is nothing left to clean up. Treat it as nothing to do, log a warning naming the attachment and the missing extension, and let the reconciler remove the finalizer so the record can finally go.

Fixes halo-dev#6380
Copilot AI lite review requested due to automatic review settings September 7, 2026 11:09

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@sonarqubecloud

sonarqubecloud Bot commented Sep 7, 2026

Copy link
Copy Markdown

@ruibaby
ruibaby requested a review from JohnNiang September 9, 2026 09:42
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.

存储删除策略后,后台日志报404

2 participants