Repository navigation
fix(server): decrement device counts only by what a cleanup deleted - #7607
Merged
Merged
Conversation
This comment has been minimized.
This comment has been minimized.
…leted The removed-device and ephemeral cleanups listed the devices to purge, deleted them, and then lowered each namespace's device count by the number they had listed. When two runs overlap, the second run's DELETE waits on the first one's row locks and then deletes nothing, yet it still subtracted its whole list, so the counts dropped twice and stayed wrong until the 03:00 count sync. Scheduled runs do not overlap: both jobs are registered unique, which holds a Redis lock across replicas. A run queued outside the scheduler does, such as the e2e suite's RunCron or an asynq CLI enqueue, and so does any run when SHELLHUB_ASYNQ_UNIQUENESS_TIMEOUT is 0. DeviceDeleteMany now returns the devices it actually deleted, each with its namespace and status, and both cleanups count from that. DeviceDelete keeps its contract on top of it.
otavio
force-pushed
the
fix/device-cleanup-deleted-counts
branch
from
October 19, 2026 00:36
a8877bb to
57603f4
Compare
Member
Author
|
/review |
|
Claude finished @otavio's task in 1m 56s —— View job Code Review CompleteReviewed 6 files on two axes: Standards (repo rules, Go conventions, tests, code smells) and Correctness (security and runtime defects). No new issues found, and the code looks good as it stands. The Spec axis did not run because the PR closes no issue and its commit trailers cite none, so there is nothing to check it against. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Both device cleanups lowered each namespace's device count by the number of devices they listed. Two overlapping runs list the same devices, but the second run's DELETE blocks on the first run's row locks and then deletes nothing. It still subtracted its whole list, so the count dropped twice and stayed wrong until the 03:00 count sync.
DeviceDeleteManynow runsDELETE ... RETURNING id, namespace_id, status, so it reports only rows this call removed.DeviceDeletekeeps itsErrNoDocumentscontract on top of it.Scheduled runs don't overlap, because both jobs are registered
asynq.Unique(), which holds a Redis lock across replicas. Overlap takes a run queued outside the scheduler (the e2e suite'sRunCron, an asynq CLI enqueue), orSHELLHUB_ASYNQ_UNIQUENESS_TIMEOUT=0. The automated review of #7600 raised it, since that PR's cleanup tests trigger the crons by hand while the scheduler is still running.Evidence
Before: the new unit cases list three devices and have the store delete fewer, as a concurrent run would leave it. On the old code both cleanups subtracted all three:
After:
go test ./api/services/passes, and so doesTestPgStore/DeviceStore, including two new store cases:returns_the_namespace_and_status_of_each_device_it_deletedleaves_out_a_device_an_earlier_call_already_deletedgolangci-lint reports 0 issues and
go mod tidy -diffis clean.Merge Danger
Door: two-way
No migration, wire format or API change.
DeviceDeleteManyis a server-internal store method; cloud doesn't call it.Blast Radius: narrow
Only the two cleanup crons and
DeviceDeletego through the changed method.