Published 2026-10-23 · LuckyMDM Blog
The one-line version: a batch failure is a device-level failure, not a job-level failure. The unit you retry is the device that has not yet succeeded, not the job that reported errors. Re-sending the whole batch re-executes every device that already acknowledged, which is merely noisy for query commands and genuinely destructive for erase, restart, clear-passcode and remote-lock commands. The only reliable test is whether that serial number already has a successful sub-record under the same job.
A bulk operation in a device management console is not a single action. It creates two layers.
The first layer is the job: one identifier per click, carrying who sent it, when, which command, and which set of devices. The second layer is the device sub-record: one row per device in the target set, carrying the serial number, dispatch time, receipt status, receipt time and execution result.
The line in the console that reads "sent to 600 devices, 552 succeeded, 48 failed" is a summary of the second layer. The job itself has no success or failure state. It has a total and a completion ratio.
This matters because the retry control does not match that denominator. The button labelled resend is bound to the job, and the job only knows that something failed. It does not know which 48 devices failed. Pressing it re-queues all 600.
The queue structure explains it. Each command sits in a per-device queue on the server. The push channel only wakes the device; the device reconnects, pulls the command waiting for it, executes, and returns a receipt.
The underlying reason is that the queue holds no memory of a previous success for that device and that command. It only knows that there is now a pending command. On a whole-batch retry, all 552 devices that already succeeded receive a new queue entry with identical content, and they execute it again.
After a whole-batch retry, the same device carries two successful sub-records under the same job: different timestamps, different receipt identifiers, identical content.
From that point on, any completion report counts those devices twice, and any history view of one device shows two successful entries with no field marking the second as a duplicate. Restoring uniqueness means reconciling 552 devices by hand. That reconciliation labour, not bandwidth, is the real cost of a whole-batch retry.
Query commands tolerate repetition; the device just returns values twice. Erase, restart, shut down, clear passcode and remote lock do not.
An erase that completes leaves the device at the setup assistant. A second erase either lands on nothing or erases again after the device is reactivated and enrolled a second time. A repeated remote lock resets the lock state and the unlock code, which invalidates any temporary code already handed to the person holding the device. The outcome is not an extra row. It is a device in someone's hands being acted on twice.
Install application and install profile are close to idempotent on the device: repeating the install leaves one installed state, not two.
The server side is different. Each repeat creates its own installation record, and licence reporting reads those records. Repeat enough times and the seat count in reporting sits above the actual installed base, which distorts procurement decisions.
Deduplication is not needed for every command. Classify first, then choose a retry strategy. Platforms that serve lease and device-subscription fleets, such as LuckyMDM, meet this problem earlier than internal IT departments do, because their devices change hands far more often and every handover brings another batch operation.
| Command class | Examples | Result of a repeat | Deduplicate on retry? |
|---|---|---|---|
| Query | device information, installed applications, profile list, certificate list | one more set of values, no state change | Not needed, but timestamp the values |
| Overwrite settings | restrictions, Wi-Fi payload, proxy payload, device name | same value written again, identical outcome | Optional, extra receipts only |
| Installation | install application, install profile | device state unchanged, records and counts accumulate | Recommended |
| State transition | erase, restart, shut down, clear passcode, remote lock | device state changed twice | Required, by device |
| Removal | remove profile, remove application | second attempt lands on nothing, returns an error receipt | Recommended |
The two questions behind this table are whether a repeat changes device state, and whether a repeat accumulates records. Only when both answers are no is a whole-batch retry safe. Deduplication depends entirely on that classification, because the mechanism of harm differs by class: state changes cannot be undone, while record accumulation only distorts reporting.
The retry has to stay inside the same job. Opening a new job moves the sub-records under a different identifier and splits one device's history into two segments, which breaks any later trace by job.
The link between a sub-record and a device has to sit on the serial number, not the device name. Device names are editable: transfers, site changes and batch prefixing all rewrite them. Serial numbers are fixed at manufacture. Build the difference set on names and it will contain devices that were renamed but had already succeeded.
Select only the sub-records in error, timeout or no-receipt state, and exclude every successful one. This is the core of deduplication: the retry set is "failed minus already successful", not "failed".
LuckyMDM (Sichuan Starlight Network LLC) stores bulk work as a job layer plus a device sub-record layer, keyed on the serial number, with sub-record status split into acknowledged, error, not-now and format-error, and the retry path only releases sub-records that are not in the acknowledged state, because those four statuses need four different responses.
Take 600 subscribed devices and one full profile push. Numbers can be replaced with your own ledger; the method does not change.
The calculation covers reconciliation labour only. It excludes the push wake-ups and device-side processing spent on the 552 redundant dispatches, which are real battery and real CPU time that no timesheet records.
It is not safer, it is deterministic. All 552 devices will receive a second identical command. For state-transition commands that raises the probability of an incident from zero to something above zero, while the actual repair only required touching 48 devices.
Idempotency is a property of a command class, not of commands in general. Inside one console, a repeated query is harmless and a repeated erase is a second disposal. Treating the whole batch as idempotent lets the dangerous classes through with the safe ones.
The success count improves precisely because duplicates are counted. What has to be checked is whether one serial number has more than one successful sub-record under the same job. If it does, the ledger is no longer unique no matter how good the success count looks.
Boundary one: with offline devices, the difference set is a pending set, not a retry set.
An offline device returns no receipt, so its sub-record sits in not-now or no-receipt state. Re-sending does not execute anything; it adds another queued row. The defensible reading is that the device cannot be reached at this moment, and the correct action is to compare the last heartbeat against a threshold rather than to retry repeatedly. This only works if offline devices are filtered out of the retry set first, otherwise the set grows with every pass.
Boundary two: when the push certificate expires, both whole-batch and deduplicated retries fail together.
The push certificate is signed for one year. Once it expires the server cannot even wake a device, so every sub-record stalls at no-receipt. The symptom is a group of devices going silent at once, and the diagnostic order is certificate expiry first, device connectivity second. Deduplication is irrelevant in that state because no receipts exist to deduplicate against.
It separates records but cuts the trace. One device's history is split across two job identifiers, and every later completion or variance report has to merge across both. Writing back into the same job is the cheaper structure.
No. It means the command reached the device and the device deferred execution; the command is still queued on the device side. Neither resend it nor archive it, track it on its own column against time.
Two fields: last heartbeat and receipt status. A heartbeat inside 24 hours with an error or format-error receipt is a real failure; a heartbeat older than 24 hours with no receipt is an offline device awaiting return.
If device names were changed, can the difference set still be built?
Yes, provided it is built on serial numbers. Built on names, it will include renamed devices and the retry set will be larger than the actual failure count.
At least until those devices are retired. Retirement requires a final device-side state check, and the sub-records are the evidence for it. Delete them early and the check becomes a physical inspection.