Skip to content

Reworked Windows profile delete batching - #44047

Merged
getvictor merged 5 commits into
mainfrom
victor/42545-delete-batch
Apr 24, 2026
Merged

Reworked Windows profile delete batching#44047
getvictor merged 5 commits into
mainfrom
victor/42545-delete-batch

Conversation

@getvictor

@getvictor getvictor commented Apr 23, 2026

Copy link
Copy Markdown
Member

Related issue: Resolves #42545

This rework does not significantly improve the worst case performance, but it does improve some cases (like lower number of hosts with a lot of profiles).

Checklist for submitter

If some of the following don't apply, delete the relevant line.

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

Testing

Summary by CodeRabbit

  • Performance Improvements
    • Improved batch deletion for Windows MDM configuration profiles to handle very large-scale cleanup with fewer database updates.
    • Replaced per-profile update loops with multi-profile batched updates to reduce update overhead and improve determinism.
  • Tests
    • Added tests validating multi-profile batch delete behavior and ensuring each queued delete command is correctly targeted.

@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@getvictor

Copy link
Copy Markdown
Member Author

/agentic_review

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Apr 23, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Remediation recommended

1. Rows slice not preallocated🐞 Bug ➹ Performance
Description
cancelWindowsHostInstallsForDeletedMDMProfiles builds the flattened rows slice via repeated append
with zero initial capacity, causing extra allocations/copies and added GC pressure on large deletes.
This runs inside a transaction, so the extra CPU/latency can directly extend lock/transaction
duration.
Code

server/datastore/mysql/microsoft_mdm.go[R1495-1504]

+	var rows []pendingRemoveRow
for profUUID, target := range enqueuedTargets {
-		if err := common_mysql.BatchProcessSimple(target.hostUUIDs, windowsMDMProfileDeleteBatchSize, func(batch []string) error {
-			upStmt, upArgs, err := sqlx.In(
-				`UPDATE host_mdm_windows_profiles
-				SET operation_type = ?, status = ?, command_uuid = ?, detail = ''
-				WHERE profile_uuid = ? AND host_uuid IN (?)`,
-				fleet.MDMOperationTypeRemove, fleet.MDMDeliveryPending, target.cmdUUID,
-				profUUID, batch,
-			)
-			if err != nil {
-				return ctxerr.Wrap(ctx, err, "building IN for phase 2 update")
-			}
-			if _, err := tx.ExecContext(ctx, upStmt, upArgs...); err != nil {
-				return ctxerr.Wrap(ctx, err, "updating host profiles to remove")
+		for _, hostUUID := range target.hostUUIDs {
+			rows = append(rows, pendingRemoveRow{
+				hostUUID:    hostUUID,
+				profileUUID: profUUID,
+				cmdUUID:     target.cmdUUID,
+			})
+		}
+	}
Evidence
The new code constructs a potentially large rows slice without reserving capacity, even though
operations in this path are explicitly batched up to 10,000 rows. Go slices grown by repeated
append will reallocate/copy multiple times as they expand, which is avoidable here.

server/datastore/mysql/microsoft_mdm.go[24-32]
server/datastore/mysql/microsoft_mdm.go[1490-1506]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`rows` is built via repeated `append` without reserving capacity, creating avoidable allocations and copies during large Windows profile deletions.
### Issue Context
This code runs inside `cancelWindowsHostInstallsForDeletedMDMProfiles` during phase-2 cleanup, and batch size is 10,000.
### Fix Focus Areas
- server/datastore/mysql/microsoft_mdm.go[1490-1506]
### Suggested fix
Preallocate `rows` with a reasonable capacity hint before the nested loops. Options:
- One-pass upper bound: `rows = make([]pendingRemoveRow, 0, len(rowsToRemove))` (safe upper bound already computed earlier).
- Two-pass exact sizing: first sum `len(target.hostUUIDs)` for `enqueuedTargets`, then `make(..., 0, total)`.
Keep behavior identical; only reduce allocations.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Missing multi-profile delete test 🐞 Bug ⚙ Maintainability
Description
The new cross-profile batched UPDATE (tuple IN + CASE) is exercised when multiple Windows profiles
are deleted in one call (e.g., deleting a team), but existing tests primarily cover single-profile
deletion. This leaves the new multi-profile batching behavior unverified by automated tests.
Code

server/datastore/mysql/microsoft_mdm.go[R1506-1542]

+	if err := common_mysql.BatchProcessSimple(rows, windowsMDMProfileDeleteBatchSize, func(batch []pendingRemoveRow) error {
+		// Collect the profile_uuid -> cmd_uuid mapping needed by this batch. Most
+		// batches span 1 to N profiles; we only need one CASE arm per distinct
+		// profile in the batch.
+		profileCmds := make(map[string]string)
+		for _, r := range batch {
+			profileCmds[r.profileUUID] = r.cmdUUID
+		}
+
+		var sb strings.Builder
+		sb.WriteString(`UPDATE host_mdm_windows_profiles
+			SET operation_type = ?,
+			    status = ?,
+			    detail = '',
+			    command_uuid = CASE profile_uuid`)
+		args := make([]any, 0, 2+2*len(profileCmds)+2*len(batch))
+		args = append(args, fleet.MDMOperationTypeRemove, fleet.MDMDeliveryPending)
+		for profUUID, cmdUUID := range profileCmds {
+			sb.WriteString(" WHEN ? THEN ?")
+			args = append(args, profUUID, cmdUUID)
+		}
+		// ELSE command_uuid is defensive: WHERE restricts the update to rows
+		// whose profile_uuid is present in profileCmds, so in practice every
+		// updated row matches a WHEN arm.
+		sb.WriteString(` ELSE command_uuid END
+			WHERE (host_uuid, profile_uuid) IN (`)
+		for i, r := range batch {
+			if i > 0 {
+				sb.WriteByte(',')
  }
-			return nil
-		}); err != nil {
-			return err
+			sb.WriteString("(?,?)")
+			args = append(args, r.hostUUID, r.profileUUID)
+		}
+		sb.WriteByte(')')
+
+		if _, err := tx.ExecContext(ctx, sb.String(), args...); err != nil {
+			return ctxerr.Wrap(ctx, err, "updating host profiles to remove")
Evidence
Team deletion collects all Windows profiles for the team and calls
cancelWindowsHostInstallsForDeletedMDMProfiles with multiple profile UUIDs, which is exactly the
scenario the new multi-profile batching targets. The existing test coverage shown deletes Windows
profiles one at a time, so it won’t validate the correctness of the new CASE/tuple-IN update across
multiple profiles in a single invocation.

server/datastore/mysql/teams.go[218-243]
server/datastore/mysql/mdm_test.go[9014-9121]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new multi-profile batching SQL (tuple IN + CASE across profiles) is not directly covered by tests for the multi-profile deletion path.
### Issue Context
When deleting a team, Fleet deletes multiple Windows profiles in one call and runs `cancelWindowsHostInstallsForDeletedMDMProfiles` with a slice of many `profileUUIDs`.
### Fix Focus Areas
- server/datastore/mysql/teams.go[218-243]
- server/datastore/mysql/microsoft_mdm.go[1479-1547]
- server/datastore/mysql/mdm_test.go[9014-9121]
### Suggested test
Add/extend a datastore test to:
1. Create >=2 Windows profiles in the same team.
2. Assign both to multiple Windows hosts such that phase-2 removal applies.
3. Trigger deletion in a single call that passes both profile UUIDs (e.g., call the team path or directly call `cancelWindowsHostInstallsForDeletedMDMProfiles` with multiple UUIDs).
4. Assert that host_mdm_windows_profiles rows for *each* profile are flipped to `operation_type=remove`, `status=pending`, and have the expected `command_uuid` per profile.
This ensures the CASE mapping and tuple-IN filter remain correct as the batching logic evolves.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The change raises windowsMDMProfileDeleteBatchSize to 10000 and rewrites cancelWindowsHostInstallsForDeletedMDMProfiles phase‑2 to flatten all (host_uuid, profile_uuid, cmd_uuid) tuples from enqueued targets, sort profile UUIDs for deterministic SQL generation, and emit batched multi‑profile UPDATE statements that set operation_type/status, compute command_uuid using a CASE profile_uuid expression, and restrict affected rows via a composite (host_uuid, profile_uuid) IN (...) predicate instead of iterating per profile. Tests were added/refactored to exercise multi‑profile deletion batching.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Reworked Windows profile delete batching' accurately and concisely describes the main change—refactoring the Windows MDM profile deletion mechanism to use batched operations instead of per-profile iterations.
Description check ✅ Passed The PR description covers required checklist items including a changes file, automated tests with host isolation verification, and manual QA, though some template sections (security/validation, database checks) are not explicitly addressed.
Linked Issues check ✅ Passed The code changes implement a batched deletion approach for Windows MDM profiles that directly addresses the performance issues identified in #42545 for large-scale deployments (20K hosts with multiple profiles).
Out of Scope Changes check ✅ Passed All changes are directly related to the batched Windows MDM profile deletion mechanism specified in #42545; the batch size constant, SQL logic optimization, test coverage, and changelog entry are all within scope.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch victor/42545-delete-batch

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.

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

Reworks batching for Windows MDM profile deletion to better utilize batch updates and increase the configured batch size while staying under MySQL placeholder limits.

Changes:

  • Increase windowsMDMProfileDeleteBatchSize from 5,000 to 10,000 with updated rationale.
  • Replace per-profile batched UPDATE loop with a single batched UPDATE across profiles using (host_uuid, profile_uuid) IN (...) and CASE to set command_uuid.

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

Comment thread server/datastore/mysql/microsoft_mdm.go Outdated
Comment thread server/datastore/mysql/microsoft_mdm.go Outdated
Comment thread server/datastore/mysql/microsoft_mdm.go Outdated

@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

🧹 Nitpick comments (1)
server/datastore/mysql/microsoft_mdm.go (1)

1495-1547: Stream pending-remove batches instead of materializing all rows.

rowsToRemove and targets already hold the affected host/profile pairs; rows duplicates the full set before batching. For large deletes, flush fixed-size batches while iterating enqueuedTargets to keep memory bounded.

♻️ Proposed refactor
-	var rows []pendingRemoveRow
-	for profUUID, target := range enqueuedTargets {
-		for _, hostUUID := range target.hostUUIDs {
-			rows = append(rows, pendingRemoveRow{
-				hostUUID:    hostUUID,
-				profileUUID: profUUID,
-				cmdUUID:     target.cmdUUID,
-			})
-		}
-	}
-
-	if err := common_mysql.BatchProcessSimple(rows, windowsMDMProfileDeleteBatchSize, func(batch []pendingRemoveRow) error {
+	updatePendingRemoveBatch := func(batch []pendingRemoveRow) error {
 		// Collect the profile_uuid -> cmd_uuid mapping needed by this batch. Most
 		// batches span 1 to N profiles; we only need one CASE arm per distinct
 		// profile in the batch.
 		profileCmds := make(map[string]string)
 		for _, r := range batch {
@@
 		if _, err := tx.ExecContext(ctx, sb.String(), args...); err != nil {
 			return ctxerr.Wrap(ctx, err, "updating host profiles to remove")
 		}
 		return nil
-	}); err != nil {
-		return err
 	}
+
+	batch := make([]pendingRemoveRow, 0, windowsMDMProfileDeleteBatchSize)
+	for profUUID, target := range enqueuedTargets {
+		for _, hostUUID := range target.hostUUIDs {
+			batch = append(batch, pendingRemoveRow{
+				hostUUID:    hostUUID,
+				profileUUID: profUUID,
+				cmdUUID:     target.cmdUUID,
+			})
+			if len(batch) == windowsMDMProfileDeleteBatchSize {
+				if err := updatePendingRemoveBatch(batch); err != nil {
+					return err
+				}
+				batch = batch[:0]
+			}
+		}
+	}
+	if len(batch) > 0 {
+		if err := updatePendingRemoveBatch(batch); err != nil {
+			return err
+		}
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/datastore/mysql/microsoft_mdm.go` around lines 1495 - 1547, Currently
the code materializes all pendingRemoveRow entries into "rows" before calling
common_mysql.BatchProcessSimple, which duplicates memory; instead stream and
flush fixed-size batches as you iterate "enqueuedTargets": create a local
[]pendingRemoveRow "batch" and for each profUUID,hostUUID append to batch, and
whenever len(batch) == windowsMDMProfileDeleteBatchSize call the existing
batch-processing logic (the body that builds profileCmds map, strings.Builder
SQL, args and calls tx.ExecContext) on that batch and then reset batch =
batch[:0]; after the loops process any remaining entries in batch the same way.
Keep the same variable names (enqueuedTargets, pendingRemoveRow,
windowsMDMProfileDeleteBatchSize, profileCmds, tx.ExecContext) and preserve
error wrapping (ctxerr.Wrap) and return behavior.
🤖 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/datastore/mysql/microsoft_mdm.go`:
- Around line 28-30: Update the explanatory comment that estimates placeholder
counts for the batched UPDATE (the "batched UPDATE with tuple IN + CASE per
profile" comment) to use the accurate formula "2 + 2*distinctProfiles + 2*rows"
and give the correct worst-case example: with 10,000 rows and 10,000 distinct
profiles this yields 40,002 placeholders (still < 65,535). Locate the comment
near the batched UPDATE logic and replace the current "~20,000" estimate and
text with the corrected formula and example so the documentation reflects the
true headroom.

---

Nitpick comments:
In `@server/datastore/mysql/microsoft_mdm.go`:
- Around line 1495-1547: Currently the code materializes all pendingRemoveRow
entries into "rows" before calling common_mysql.BatchProcessSimple, which
duplicates memory; instead stream and flush fixed-size batches as you iterate
"enqueuedTargets": create a local []pendingRemoveRow "batch" and for each
profUUID,hostUUID append to batch, and whenever len(batch) ==
windowsMDMProfileDeleteBatchSize call the existing batch-processing logic (the
body that builds profileCmds map, strings.Builder SQL, args and calls
tx.ExecContext) on that batch and then reset batch = batch[:0]; after the loops
process any remaining entries in batch the same way. Keep the same variable
names (enqueuedTargets, pendingRemoveRow, windowsMDMProfileDeleteBatchSize,
profileCmds, tx.ExecContext) and preserve error wrapping (ctxerr.Wrap) and
return behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 28b457f6-caad-4a0b-b312-f70df2973085

📥 Commits

Reviewing files that changed from the base of the PR and between 255be3f and 721c5f8.

📒 Files selected for processing (1)
  • server/datastore/mysql/microsoft_mdm.go

Comment thread server/datastore/mysql/microsoft_mdm.go Outdated
@codecov

codecov Bot commented Apr 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.30435% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.75%. Comparing base (bf3a12a) to head (3efe2e5).
⚠️ Report is 60 commits behind head on main.

Files with missing lines Patch % Lines
server/datastore/mysql/microsoft_mdm.go 91.30% 3 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #44047      +/-   ##
==========================================
- Coverage   66.83%   66.75%   -0.09%     
==========================================
  Files        2609     2622      +13     
  Lines      210432   210963     +531     
  Branches     9292     9292              
==========================================
+ Hits       140645   140828     +183     
- Misses      56969    57313     +344     
- Partials    12818    12822       +4     
Flag Coverage Δ
backend 68.52% <91.30%> (-0.10%) ⬇️

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.

Three Copilot review points applied:

1. Fix the placeholder-count doc on windowsMDMProfileDeleteBatchSize. The
   comment's "~20,000" was the realistic case (tens of profiles); the
   mathematical worst case (10,000 distinct profiles sharing a 10,000-row
   batch) is 40,002 placeholders. Document the full formula
   2 + 2*distinctProfilesInBatch + 2*rowsInBatch so future batch-size
   tuning has the correct bound.

2. Pre-allocate the flattened `rows` slice to the known total count. The
   previous unbounded `append` triggered repeated reallocations when many
   profiles or hosts were involved.

3. Generate SQL in deterministic order. Iterating enqueuedTargets and
   profileCmds via map range produced non-deterministic CASE-arm and
   IN-tuple order across calls, creating different query text for
   same-shape batches and reducing MySQL plan-cache / observability
   digest stability. Sort profile UUIDs before iterating both the outer
   flatten loop and the inner CASE generation.
@getvictor
getvictor marked this pull request as ready for review April 23, 2026 18:11
@getvictor
getvictor requested a review from a team as a code owner April 23, 2026 18:11

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@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

🧹 Nitpick comments (1)
server/datastore/mysql/microsoft_mdm_test.go (1)

1976-1984: Helper is not team-scoped — safe today, fragile later.

windowsProfileUUIDByName filters by name only. The unique constraint on mdm_windows_configuration_profiles.name is per-team, so a future test that seeds same-named profiles across teams (or a test running against an already-populated DB) would silently hit whichever row MySQL returns first, or fail with "more than one row" from sqlx.GetContext. All current callers create profiles at no-team scope so it's fine now, but consider accepting an optional teamID *uint and adding AND team_id = ? (with 0 for no-team) to harden the helper before it gets reused.

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

In `@server/datastore/mysql/microsoft_mdm_test.go` around lines 1976 - 1984, The
helper windowsProfileUUIDByName is currently scoped only by name and should be
made team-aware to avoid ambiguous results; change its signature to accept an
optional teamID *uint, update the SQL inside ExecAdhocSQL/sqlx.GetContext to add
"AND team_id = ?" (using 0 when teamID == nil to represent no-team), and update
all callers to pass either nil or a pointer to the relevant team ID so the query
deterministically selects the correct mdm_windows_configuration_profiles row.
🤖 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/datastore/mysql/microsoft_mdm_test.go`:
- Around line 2009-2024: The docstring for rawWindowsDeleteCommandForHostProfile
is incorrect about fallback behavior: because the implementation uses
sqlx.GetContext inside ExecAdhocSQL, a missing join row yields sql.ErrNoRows
which ExecAdhocSQL/require.NoError will surface and fail the test rather than
returning empty bytes; update the comment to state that the helper will fail the
test if no matching delete command is queued (it only returns nil when
raw_command is SQL NULL), or alternatively change the implementation (replace
sqlx.GetContext with a tolerant SelectContext into a *[]byte and return an empty
slice when len == 0) — reference rawWindowsDeleteCommandForHostProfile,
ExecAdhocSQL, and sqlx.GetContext to locate the code.

---

Nitpick comments:
In `@server/datastore/mysql/microsoft_mdm_test.go`:
- Around line 1976-1984: The helper windowsProfileUUIDByName is currently scoped
only by name and should be made team-aware to avoid ambiguous results; change
its signature to accept an optional teamID *uint, update the SQL inside
ExecAdhocSQL/sqlx.GetContext to add "AND team_id = ?" (using 0 when teamID ==
nil to represent no-team), and update all callers to pass either nil or a
pointer to the relevant team ID so the query deterministically selects the
correct mdm_windows_configuration_profiles row.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 15ae0507-dee3-46f4-b69c-0cd19429c2cc

📥 Commits

Reviewing files that changed from the base of the PR and between 721c5f8 and 470ed88.

📒 Files selected for processing (3)
  • changes/42545-windows-profile-delete-batching
  • server/datastore/mysql/microsoft_mdm.go
  • server/datastore/mysql/microsoft_mdm_test.go
✅ Files skipped from review due to trivial changes (1)
  • changes/42545-windows-profile-delete-batching

Comment thread server/datastore/mysql/microsoft_mdm_test.go

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

🧹 Nitpick comments (2)
server/datastore/mysql/microsoft_mdm_test.go (2)

4727-4807: Good coverage of the new multi-profile UPDATE path.

The test exercises the CASE profile_uuid mapping by correlating each flipped row's command_uuid back to windows_mdm_commands.raw_command and asserting the LocURI belongs to that specific profile. This would catch both CASE cross-wiring and an unintended ELSE command_uuid fire (since a stale/unchanged command_uuid wouldn't join to a queued remove command with the expected LocURI). Two hosts × three profiles is enough to verify host isolation and per-profile command distinctness without bloating runtime.

One small gap worth considering: the test runs with the default windowsMDMProfileDeleteBatchSize (10000), so the multi-batch boundary in BatchProcessSimple isn't exercised here. If you want to cover the split-batch case as well, a variant that sets ds.testDeleteMDMProfilesBatchSize (or the dedicated windows knob, if one is wired) to a small value like 2 would force multiple batches over the same 6 rows and validate that per-profile CASE arms are correctly emitted in each batch.

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

In `@server/datastore/mysql/microsoft_mdm_test.go` around lines 4727 - 4807, Add a
variant of testBatchDeleteMultipleWindowsProfiles that forces the multi-batch
path by setting the datastore test batch size to a small value (e.g.
ds.testDeleteMDMProfilesBatchSize = 2) before invoking
batchSetMDMWindowsProfilesDB, run the same assertions, and then restore the
original value; locate this change in the test function
testBatchDeleteMultipleWindowsProfiles (or a new sibling test) and ensure the
small batch size drives multiple BatchProcessSimple iterations so the CASE
profile_uuid arms are exercised across batches.

1986-2007: Minor: identical ProfileName for all seeded rows reduces diagnostic signal.

All seed payloads share ProfileName: "test". That's harmless for the upsert (PK is (host_uuid, profile_uuid)), but if a future assertion fails on profile_name it'll be hard to tell rows apart. Consider deriving the name from pUUID (e.g. "test-" + pUUID) so test failure messages point at the specific profile.

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

In `@server/datastore/mysql/microsoft_mdm_test.go` around lines 1986 - 2007, The
seeded payloads in installWindowsProfilesAsVerified use a constant ProfileName
"test" which reduces diagnostic signal; update the loop that builds
fleet.MDMWindowsBulkUpsertHostProfilePayload so ProfileName is derived from the
profile UUID (e.g. concatenate a prefix like "test-" with pUUID) instead of the
constant, leaving other fields and the call to
ds.BulkUpsertMDMWindowsHostProfiles(t.Context(), payloads) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@server/datastore/mysql/microsoft_mdm_test.go`:
- Around line 4727-4807: Add a variant of testBatchDeleteMultipleWindowsProfiles
that forces the multi-batch path by setting the datastore test batch size to a
small value (e.g. ds.testDeleteMDMProfilesBatchSize = 2) before invoking
batchSetMDMWindowsProfilesDB, run the same assertions, and then restore the
original value; locate this change in the test function
testBatchDeleteMultipleWindowsProfiles (or a new sibling test) and ensure the
small batch size drives multiple BatchProcessSimple iterations so the CASE
profile_uuid arms are exercised across batches.
- Around line 1986-2007: The seeded payloads in installWindowsProfilesAsVerified
use a constant ProfileName "test" which reduces diagnostic signal; update the
loop that builds fleet.MDMWindowsBulkUpsertHostProfilePayload so ProfileName is
derived from the profile UUID (e.g. concatenate a prefix like "test-" with
pUUID) instead of the constant, leaving other fields and the call to
ds.BulkUpsertMDMWindowsHostProfiles(t.Context(), payloads) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3b539fa6-1b2b-4a7a-a81d-c16173cb6a24

📥 Commits

Reviewing files that changed from the base of the PR and between 470ed88 and 3efe2e5.

📒 Files selected for processing (1)
  • server/datastore/mysql/microsoft_mdm_test.go

@getvictor
getvictor merged commit 43552b8 into main Apr 24, 2026
48 checks passed
@getvictor
getvictor deleted the victor/42545-delete-batch branch April 24, 2026 16:43
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.

Reference architecture cannot sustain 20K Windows MDM hosts due to excessive MySQL writer load

3 participants