fix: Optimize cleanup jobs, eliminate raw ES client usage, add test coverage#2267
fix: Optimize cleanup jobs, eliminate raw ES client usage, add test coverage#2267niemyjski wants to merge 7 commits into
Conversation
154223e to
7788c75
Compare
There was a problem hiding this comment.
Pull request overview
This PR refactors cleanup jobs to rely on repository abstractions, improves duplicate stack cleanup behavior, and adds integration coverage for cleanup/repository operations.
Changes:
- Reworked orphaned-data and cleanup jobs with lock renewal, cancellation checks, and repository-based deletes/updates.
- Added event repository helpers for bulk deletion, stack reassignment, and distinct-id aggregation.
- Added integration tests for cleanup pagination, retention, duplicate signatures, and event repository operations.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/Exceptionless.Core/Jobs/CleanupDataJob.cs |
Extends lock duration and renews locks during paged cleanup/retention loops. |
src/Exceptionless.Core/Jobs/CleanupOrphanedDataJob.cs |
Replaces direct Elasticsearch calls with repository methods for orphan cleanup and duplicate-stack fixing. |
src/Exceptionless.Core/Repositories/EventRepository.cs |
Adds bulk delete, stack reassignment, and composite aggregation helpers. |
src/Exceptionless.Core/Repositories/Interfaces/IEventRepository.cs |
Exposes new event repository cleanup/query APIs and composite cursor type. |
src/Exceptionless.Core/Repositories/StackRepository.cs |
Adds duplicate signature aggregation lookup. |
src/Exceptionless.Core/Repositories/Interfaces/IStackRepository.cs |
Exposes duplicate signature lookup API. |
tests/Exceptionless.Tests/Jobs/CleanupDataJobTests.cs |
Adds cleanup pagination and retention integration coverage. |
tests/Exceptionless.Tests/Jobs/CleanupOrphanedDataJobTests.cs |
Adds integration coverage for orphan cleanup and duplicate stack merging. |
tests/Exceptionless.Tests/Repositories/EventRepositoryTests.cs |
Adds coverage for distinct ids, stack reassignment, and bulk delete helpers. |
tests/Exceptionless.Tests/Repositories/StackRepositoryTests.cs |
Adds duplicate signature repository coverage. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
7788c75 to
3c5880b
Compare
|
Merged origin/main and addressed the outstanding review feedback in 92fa434. Summary:
Verification:
All review threads are resolved. |
92fa434 to
281071e
Compare
|
Production-readiness pass complete on f6fcc4b.
Production-readiness verdict: READY. |
…ction-readiness-20260715
|
Production-readiness refresh complete on bd560b0.
Production-readiness verdict: READY. PR remains open and unmerged. |
|
Follow-up reviewer audit complete on c2bcdc6. Feedback ledger
RCA and current design proof
Thermo-nuclear review
Verification
Verdict: READY. No code changes were required in this follow-up audit; the PR remains open and unmerged. |
Summary
Comprehensive optimization of cleanup jobs: eliminate direct Elasticsearch client usage from jobs, fix critical bugs, preserve cleanup correctness under concurrent ingestion, and add full integration test coverage.
Critical Bug Fixes
@min_count:2→@min:2inGetDuplicateSignaturesAsyncThe
@min_countsyntax is silently ignored by Foundatio Parsers, causing the aggregation to return ALL signature hashes (not just duplicates). This would have causedFixDuplicateStacksAsyncto treat every stack as a duplicate on the next run.FixDuplicateStacksAsynconly ran one batch (regression from refactor)The original code looped until
GetDuplicateSignaturesAsyncreturned empty. The refactor broke this. Restored the loop with:ImmediateConsistency()onCountAsyncinsideGetDuplicateSignaturesAsync(one refresh per batch, matching the originalIndices.RefreshAsynccall pattern — NOT per item)ReassignStackAsyncdata-loss hazard on empty sequenceIf
sourceStackIdswas empty,PatchAllAsyncwould have no stack filter and would reassign ALL events to the target stack. Added materialization + early return guard.FixDuplicateStacksAsyncevent-first orderingEvent reassignment completes before a duplicate stack is finalized as a redirect tombstone. If event reassignment fails, duplicate stacks remain visible and no data is lost.
GetDistinctFieldValuesAsynccursor correctnessDistinct event identifiers use composite aggregation pagination with an explicit next-value cursor so callers reliably detect the end of pagination.
Architecture (eliminate raw ES client from jobs)
CleanupOrphanedDataJobto use repository methods exclusivelyGetDistinctFieldValuesAsyncusing composite aggregation (encapsulated in the repository — composite aggregation is not in Foundatio's DSL, so raw client use is justified and documented)RemoveAllByProjectIdsAsync/RemoveAllByOrganizationIdsAsyncandRemoveAllByStackIdsAsynctoIEventRepositoryReassignStackAsyncusing a parameterized Painless script and strict post-write verificationGetDuplicateSignaturesAsynctoIStackRepositoryConcurrency and lossless reconciliation
Stackpersistence so stale full-document saves cannot overwrite cleanup mergesindex_not_found_exception; other shard/index verification failures fail closedOther Fixes
OperationCanceledExceptionhandling before the intentionally broad per-signature catchis_deleted:falsefilters where repository soft-delete filtering applies:{Message}to error log format stringsMerged onto current main
Merged the latest
origin/mainwith a normal merge commit and kept the final diff limited to the intended cleanup, repository, serialization, and test files.Test Coverage
Coverage includes: