Skip to content

Moved cleanup activities logic to activity bounded context. - #40663

Merged
getvictor merged 7 commits into
mainfrom
victor/38536-cleanup-activities
Feb 27, 2026
Merged

Moved cleanup activities logic to activity bounded context.#40663
getvictor merged 7 commits into
mainfrom
victor/38536-cleanup-activities

Conversation

@getvictor

@getvictor getvictor commented Feb 26, 2026

Copy link
Copy Markdown
Member

Related issue: Resolves #38536

Split the activities cleanup job from the queries cleanup job.

Checklist for submitter

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.
    • Present in previous PR

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

Summary by CodeRabbit

Release Notes

  • New Features

    • Added automated cleanup job for expired live queries based on activity expiration settings.
  • Improvements

    • Refactored activity data cleanup to use a dedicated service for better reliability and maintainability.
    • Enhanced scheduled cleanup operations with improved separation of concerns for activity and live query management.

@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Feb 26, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai

coderabbitai Bot commented Feb 26, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR refactors activity cleanup operations by introducing a new CleanupExpiredActivities method in the activity bounded context package hierarchy. It separates the previous combined cleanup of activities and associated data into two distinct operations: activity cleanup handled through the activity service interface, and live queries cleanup handled through a renamed datastore method. The cron scheduler is updated to receive an activitySvc parameter to enable activity cleanup invocation through the bounded context rather than directly on the datastore.

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive All changes align with the stated objective of moving activity cleanup logic to the bounded context; however, the addition of CleanupExpiredLiveQueries (which targets live queries, not activities) appears to extend beyond the scope of task 2. Clarify whether the live queries cleanup is part of the refactoring scope or a separate concern; document the rationale for decoupling activity cleanup from live query cleanup.
Description check ❓ Inconclusive The PR description is incomplete: it lacks sections for changes files, input validation, testing details, and database migration checks despite the template requiring them. Complete the description by filling out all required template sections. Verify whether changes files were added and provide more specific details about the tests that were added or updated.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and specifically summarizes the main change: moving cleanup activities logic into the activity bounded context, which aligns with the primary objectives.
Linked Issues check ✅ Passed The PR implements task 2 (split activity cleanup from CleanupActivitiesAndAssociatedData to bounded context) by adding CleanupExpiredActivities to the activity bounded context and creating cleanup_live_queries cron job, fulfilling the stated objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch victor/38536-cleanup-activities

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/datastore/mysql/activities.go (1)

311-317: ⚠️ Potential issue | 🟠 Major

Bound batch size in SQL selection to avoid unbounded memory growth.

Line 311, Line 340, and Line 369 materialize full ID lists before chunking. On large tables this can spike memory and make cleanup runs too heavy. Prefer iterative SELECT ... LIMIT ? + delete loops so memory and lock windows stay bounded.

Suggested fix pattern
- var allUnsavedQueryIDs []uint
- if err := sqlx.SelectContext(ctx, ds.reader(ctx), &allUnsavedQueryIDs, selectUnsavedQueryIDs, expiredWindowDays); err != nil {
-   return ctxerr.Wrap(ctx, err, "selecting expired unsaved query IDs")
- }
- unsavedQueryIter := slices.Chunk(allUnsavedQueryIDs, deleteIDsBatchSize)
- for unsavedQueryIDs := range unsavedQueryIter {
+ for {
+   var unsavedQueryIDs []uint
+   const selectUnsavedQueryIDsBatch = `
+     SELECT id
+     FROM queries
+     WHERE NOT saved
+       AND created_at < DATE_SUB(NOW(), INTERVAL ? DAY)
+     ORDER BY id
+     LIMIT ?`
+   if err := sqlx.SelectContext(ctx, ds.reader(ctx), &unsavedQueryIDs, selectUnsavedQueryIDsBatch, expiredWindowDays, deleteIDsBatchSize); err != nil {
+     return ctxerr.Wrap(ctx, err, "selecting expired unsaved query IDs")
+   }
+   if len(unsavedQueryIDs) == 0 {
+     break
+   }
    const deleteStmt = `DELETE FROM queries WHERE id IN (?)`
    ...
  }

Apply the same bounded-loop approach to campaign and campaign-target cleanup sections.

Also applies to: 340-347, 369-376

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/datastore/mysql/activities.go` around lines 311 - 317, The code
currently materializes full ID arrays (using sqlx.SelectContext into
allUnsavedQueryIDs and then slices.Chunk) which can OOM on large tables; change
to an iterative bounded SELECT + delete loop that fetches up to
deleteIDsBatchSize IDs per iteration and deletes them until no rows are
returned. Specifically, replace the sqlx.SelectContext(...,
selectUnsavedQueryIDs, expiredWindowDays) + slices.Chunk usage with a loop that
calls sqlx.SelectContext(ctx, ds.reader(ctx), &batchIDs,
selectUnsavedQueryIDsWithLimit, expiredWindowDays, deleteIDsBatchSize) (or
otherwise binds LIMIT), deletes that batch, and repeats until batchIDs is empty;
apply the same pattern to the campaign and campaign-target cleanup sections (the
other blocks that materialize full ID lists) and keep using deleteIDsBatchSize
to bound memory and lock windows.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/activity/internal/mysql/activity.go`:
- Around line 205-225: The current read-then-delete in CleanupExpiredActivities
can delete a row that becomes host-linked between statements; fix it by
performing the selection and deletion inside a transaction with row locks: begin
a transaction (use sqlx.BeginTxx on ds.primary), run the select query within the
transaction using FOR UPDATE (modify the existing selectQuery to append "FOR
UPDATE") via tx.SelectContext to populate activityIDs, re-check that selected
IDs have no host links (or rely on the SELECT ... LEFT JOIN ha WHERE
ha.activity_id IS NULL FOR UPDATE), then run the DELETE within the same tx using
tx.ExecContext and commit; update uses of sqlx.SelectContext/sqlx.In to their tx
equivalents so all operations occur in the same transaction context and prevent
the race.

---

Outside diff comments:
In `@server/datastore/mysql/activities.go`:
- Around line 311-317: The code currently materializes full ID arrays (using
sqlx.SelectContext into allUnsavedQueryIDs and then slices.Chunk) which can OOM
on large tables; change to an iterative bounded SELECT + delete loop that
fetches up to deleteIDsBatchSize IDs per iteration and deletes them until no
rows are returned. Specifically, replace the sqlx.SelectContext(...,
selectUnsavedQueryIDs, expiredWindowDays) + slices.Chunk usage with a loop that
calls sqlx.SelectContext(ctx, ds.reader(ctx), &batchIDs,
selectUnsavedQueryIDsWithLimit, expiredWindowDays, deleteIDsBatchSize) (or
otherwise binds LIMIT), deletes that batch, and repeats until batchIDs is empty;
apply the same pattern to the campaign and campaign-target cleanup sections (the
other blocks that materialize full ID lists) and keep using deleteIDsBatchSize
to bound memory and lock windows.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef15ad2 and 605df50.

📒 Files selected for processing (15)
  • cmd/fleet/cron.go
  • cmd/fleet/serve.go
  • server/activity/api/cleanup_expired_activities.go
  • server/activity/api/service.go
  • server/activity/bootstrap/testing.go
  • server/activity/internal/mysql/activity.go
  • server/activity/internal/mysql/activity_cleanup_test.go
  • server/activity/internal/service/cleanup_expired_activities.go
  • server/activity/internal/service/handler_test.go
  • server/activity/internal/service/service_test.go
  • server/activity/internal/types/activity.go
  • server/datastore/mysql/activities.go
  • server/datastore/mysql/activities_test.go
  • server/fleet/datastore.go
  • server/mock/datastore_mock.go

Comment thread server/activity/internal/mysql/activity.go

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

Refactors cleanup responsibilities to align with the activity bounded-context migration by moving activity expiry deletion behind the activity service, while separating live-query cleanup into its own datastore method and cron job.

Changes:

  • Add CleanupExpiredActivities to the activity bounded context (API/service + MySQL implementation + tests).
  • Replace legacy CleanupActivitiesAndAssociatedData with CleanupExpiredLiveQueries on fleet.Datastore (and update mocks/tests).
  • Update cron wiring to run activity cleanup via activitySvc and live-query cleanup via ds.

Reviewed changes

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

Show a summary per file
File Description
server/mock/datastore_mock.go Updates datastore mock to match renamed cleanup method (CleanupExpiredLiveQueries).
server/fleet/datastore.go Replaces legacy activity cleanup API with CleanupExpiredLiveQueries in the datastore interface.
server/datastore/mysql/activities_test.go Updates MySQL datastore tests to cover CleanupExpiredLiveQueries behavior.
server/datastore/mysql/activities.go Removes legacy activity cleanup implementation; keeps live-query cleanup as CleanupExpiredLiveQueries.
server/activity/internal/types/activity.go Extends activity bounded-context datastore interface with CleanupExpiredActivities.
server/activity/internal/service/service_test.go Updates service test mocks to satisfy new datastore interface.
server/activity/internal/service/handler_test.go Updates validation-test service mock to satisfy new service interface.
server/activity/internal/service/cleanup_expired_activities.go Adds service method that delegates to the activity datastore cleanup.
server/activity/internal/mysql/activity_cleanup_test.go Adds MySQL integration tests for CleanupExpiredActivities.
server/activity/internal/mysql/activity.go Implements MySQL CleanupExpiredActivities.
server/activity/bootstrap/testing.go Updates noop store to satisfy new datastore interface for tests.
server/activity/api/service.go Adds CleanupExpiredActivitiesService to the activity service interface.
server/activity/api/cleanup_expired_activities.go Introduces API interface for activity cleanup.
cmd/fleet/serve.go Passes activitySvc into the cleanups schedule factory.
cmd/fleet/cron.go Runs activity cleanup via activitySvc and adds separate live-query cleanup job via ds.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server/fleet/datastore.go Outdated
Comment thread cmd/fleet/cron.go Outdated
Comment thread server/activity/internal/mysql/activity.go Outdated
@codecov

codecov Bot commented Feb 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 44.11765% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.27%. Comparing base (8e98a1b) to head (3d02512).
⚠️ Report is 31 commits behind head on main.

Files with missing lines Patch % Lines
cmd/fleet/cron.go 0.00% 8 Missing ⚠️
server/activity/internal/mysql/activity.go 70.00% 3 Missing and 3 partials ⚠️
...ity/internal/service/cleanup_expired_activities.go 0.00% 4 Missing ⚠️
cmd/fleet/serve.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #40663      +/-   ##
==========================================
- Coverage   66.28%   66.27%   -0.01%     
==========================================
  Files        2467     2468       +1     
  Lines      197503   197520      +17     
  Branches     8656     8763     +107     
==========================================
+ Hits       130905   130911       +6     
- Misses      54742    54754      +12     
+ Partials    11856    11855       -1     
Flag Coverage Δ
backend 68.07% <2.94%> (-0.02%) ⬇️
backend-activity 87.37% <58.33%> (-1.25%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@getvictor
getvictor marked this pull request as ready for review February 27, 2026 17:02
@getvictor
getvictor requested a review from a team as a code owner February 27, 2026 17:02
@getvictor
getvictor merged commit 593cf01 into main Feb 27, 2026
73 of 75 checks passed
@getvictor
getvictor deleted the victor/38536-cleanup-activities branch February 27, 2026 22:21
@coderabbitai coderabbitai Bot mentioned this pull request Apr 21, 2026
8 tasks
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.

Activity bounded context: Complete write operations

4 participants