From 316adb4cd078fcbd42e7f8a37055240f3c2a3b71 Mon Sep 17 00:00:00 2001 From: Magnus Jensen Date: Tue, 13 Jan 2026 13:06:33 -0500 Subject: [PATCH] randomize APNS query (#38222) **Related issue:** Resolves #36644 Randomizes the query so we get a new set of 500 every time, and also improves the index by adding a priority where clause. It should fine handle up towards 10.000 filtered entries before becoming slow, and at most we have seen 2k with a customer. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually --- changes/36644-randomize-apns-query | 1 + server/datastore/mysql/apple_mdm.go | 21 ++++++++++++++------- server/datastore/mysql/apple_mdm_test.go | 19 ++++++++++++++++--- 3 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 changes/36644-randomize-apns-query diff --git a/changes/36644-randomize-apns-query b/changes/36644-randomize-apns-query new file mode 100644 index 0000000000..21f850c749 --- /dev/null +++ b/changes/36644-randomize-apns-query @@ -0,0 +1 @@ +- Randomized APNS query to ensure all pending Apple hosts gets a push notification \ No newline at end of file diff --git a/server/datastore/mysql/apple_mdm.go b/server/datastore/mysql/apple_mdm.go index 750edf7973..17f05f8f0e 100644 --- a/server/datastore/mysql/apple_mdm.go +++ b/server/datastore/mysql/apple_mdm.go @@ -6248,12 +6248,20 @@ GROUP BY h.id` func (ds *Datastore) GetEnrollmentIDsWithPendingMDMAppleCommands(ctx context.Context) (uuids []string, err error) { const stmt = ` -SELECT DISTINCT neq.id -FROM nano_enrollment_queue neq -INNER JOIN nano_enrollments ne ON ne.id = neq.id -LEFT JOIN nano_command_results ncr ON ncr.command_uuid = neq.command_uuid AND ncr.id = neq.id -WHERE neq.active = 1 AND ne.enabled=1 AND ncr.status IS NULL -AND neq.created_at >= NOW() - INTERVAL 7 DAY +SELECT DISTINCT + neq.id +FROM + nano_enrollment_queue neq + INNER JOIN nano_enrollments ne ON ne.id = neq.id + LEFT JOIN nano_command_results ncr ON ncr.command_uuid = neq.command_uuid + AND ncr.id = neq.id +WHERE + neq.active = 1 + AND ne.enabled = 1 + AND ncr.status IS NULL + AND neq.created_at >= NOW() - INTERVAL 7 DAY + AND neq.priority IN (0, 1) +ORDER BY RAND() LIMIT 500 ` @@ -7090,7 +7098,6 @@ func (ds *Datastore) InsertHostLocationData(ctx context.Context, locData fleet.H } func (ds *Datastore) GetHostLocationData(ctx context.Context, hostID uint) (*fleet.HostLocationData, error) { - var ret fleet.HostLocationData err := sqlx.GetContext(ctx, ds.reader(ctx), &ret, "SELECT host_id, latitude, longitude FROM host_last_known_locations WHERE host_id = ?", hostID) diff --git a/server/datastore/mysql/apple_mdm_test.go b/server/datastore/mysql/apple_mdm_test.go index 90e4af9e09..09f6afca0b 100644 --- a/server/datastore/mysql/apple_mdm_test.go +++ b/server/datastore/mysql/apple_mdm_test.go @@ -7155,9 +7155,23 @@ func testGetEnrollmentIDsWithPendingMDMAppleCommands(t *testing.T, ds *Datastore err = commander.EnqueueCommand(ctx, []string{hostUUIDToUserEnrollmentID[hosts[3].UUID], hostUUIDToUserEnrollmentID[hosts[4].UUID], hostUUIDToUserEnrollmentID[hosts[5].UUID]}, rawCmd2) require.NoError(t, err) - ids, err = ds.GetEnrollmentIDsWithPendingMDMAppleCommands(ctx) + firstIds, err := ds.GetEnrollmentIDsWithPendingMDMAppleCommands(ctx) require.NoError(t, err) - require.ElementsMatch(t, []string{hosts[1].UUID, hosts[2].UUID, hostUUIDToUserEnrollmentID[hosts[3].UUID], hostUUIDToUserEnrollmentID[hosts[4].UUID], hostUUIDToUserEnrollmentID[hosts[5].UUID]}, ids) + require.ElementsMatch(t, []string{hosts[1].UUID, hosts[2].UUID, hostUUIDToUserEnrollmentID[hosts[3].UUID], hostUUIDToUserEnrollmentID[hosts[4].UUID], hostUUIDToUserEnrollmentID[hosts[5].UUID]}, firstIds) + + // Get a list of pending ID's 3 times and match against the first list, to avoid test flakiness. + // In a real world scenario it's okay for it to be the same as we will fetch it again later. + allAttemptsWereEqual := true + for range 3 { + secondIds, err := ds.GetEnrollmentIDsWithPendingMDMAppleCommands(ctx) + require.NoError(t, err) + isIdsEqual := assert.ObjectsAreEqualValues(firstIds, secondIds) + if !isIdsEqual { + allAttemptsWereEqual = false + break + } + } + require.False(t, allAttemptsWereEqual, "GetEnrollmentIDsWithPendingMDMAppleCommands returned the same result 3 times in a row") err = storage.StoreCommandReport(&mdm.Request{ EnrollID: &mdm.EnrollID{ID: hostUUIDToUserEnrollmentID[hosts[3].UUID]}, @@ -9627,5 +9641,4 @@ func testDeviceLocation(t *testing.T, ds *Datastore) { _, err = ds.GetHostLocationData(ctx, iOSHost.ID) require.True(t, fleet.IsNotFound(err)) - }