Sweeping Leftover Chunks Safely: A Checklist That Asks Who Owns Them First
Abandoned upload chunks fill storage, but a cleanup job that judges only by file age can delete a slow upload that is still working. This article proposes a checklist where ownership and activity come before age. The values are conditional design choices you should tune. Nothing here describes an existing system.
The artifact: cleanup checklist
For every stored chunk, answer these in order. Stop at the first matching outcome.
- Does the chunk belong to an upload session record? If not, it is an orphan. Go to outcome H (hold).
- Is the session in an assembling or verifying state? If so, keep it. If it has stayed there longer than an agreed stuck limit, raise an alert for a human. Never delete it.
- Has the session shown activity (a chunk confirmed, a heartbeat, a status query) within the grace period? If so, keep it.
- Otherwise the session is idle past the grace period. Mark the session expired. This is a recorded state change, not a deletion.
- On a later pass, after a second grace interval, re-read the session. If it is still expired and shows no new activity, delete its chunks. If activity returned, revert it to active and keep everything.
Outcomes: K (keep), M (mark expired), D (delete), H (hold for review).
Why two passes
A single pass has a race. The cleanup reads the session as idle at the same instant a client sends a chunk. Marking first, then re-reading later, gives late activity a chance to be seen. The delete step should also be conditional on the session still being expired at that moment. A resumed upload should win over cleanup.
Orphans are different
A chunk with no session might be a bug, a half-written session, or data from another process. Do not delete orphans automatically. List them with age and size, and let a person decide. If a later pass finds a matching session appearing after the chunk, the chunk was not an orphan after all.
Worked hypothetical example
Assume a 24 hour grace period (hypothetical) and a 27 chunk inventory:
- S1: 12 chunks, last activity 10 minutes ago, state uploading. Outcome K.
- S2: 7 chunks, idle 30 hours, state assembling. Outcome K, and flagged as possibly stuck.
- S3: 5 chunks, idle 30 hours, state uploading. First pass is M. After the next interval, if still idle, outcome D.
- S4: 3 chunks, no session record, 30 hours old. Outcome H.
Totals on pass one: 12 + 7 = 19 kept, 5 marked expired, 3 held. Nothing deleted yet. On pass two, with S3 still idle, 5 are deleted, leaving 19 kept and 3 held, which accounts for all 27. If S3's owner sent a chunk between the passes, S3 reverts to active, 0 are deleted, and 24 are kept with 3 held.
If a delete result is unclear
If a delete call times out or returns an unclear answer, do not assume it failed or succeeded, and do not repeat it blindly. List the chunk again and decide from what you find. Log the uncertainty on the session record.
Stop conditions
- The session lookup fails. Treat all chunks as keep for that run.
- Clock values look wrong, such as activity in the future.
- A pass would delete more than an agreed percentage of all stored chunks. Pause and ask a person.
Proposed acceptance tests (to be run, none performed here)
- Load the 27 chunk inventory and expect 19 keep, 5 mark, 3 hold on pass one with zero deletions.
- Send one chunk to S3 between passes and expect no deletions.
- Leave S3 idle and expect exactly 5 deletions on pass two.
- Make the session lookup fail and expect zero deletions.
- Simulate a delete timeout and expect a re-list rather than an immediate retry.
- Trigger the percentage limit and expect a pause.
These layers lower the chance of removing live work, but cannot remove it. Keep restore options and alerts alongside the checklist.