Classic ASP Temporary Upload Cleanup Without Losing Attachments
Closing a browser tab does not reliably notify the server. A durable upload workflow needs its own expiry and commitment rules so abandoned files can be removed without touching valid attachments.
Define what temporary means
An upload may be receiving bytes, ready for a form submission, being promoted to permanent storage or committed to a record. These states are not equivalent. Store a server-side upload identifier, owner, creation time, expiry and lifecycle state. Keep the storage key separate from the browser's original name.
A temporary directory is not automatically safe to empty. A user may have finished the transfer but still be completing a long form. Your retention period should reflect that workflow and your storage budget. The UI should explain expiry and let the user select a replacement when a pending object is no longer available.
Commit the attachment when the business record is saved
On final submission, verify that the current user owns the pending object and may modify the destination record. Move or copy the bytes according to your storage design and record the permanent attachment link. Do not mark an upload committed merely because the browser sent an identifier.
Filesystem operations and database writes do not form one atomic transaction. Use explicit intermediate state and make promotion retryable. If a file move succeeds but the record transaction fails, the system needs a way to reconcile that object rather than either deleting it immediately or leaving it forever.
Claim expired work before deleting anything
-- Candidate selection only; not a complete cleanup transaction:
SELECT UploadId
FROM dbo.PendingUpload
WHERE State = 'Pending'
AND ExpiresUtc < SYSUTCDATETIME();Selecting an expired row is only the beginning. Before deleting bytes, atomically claim that row for cleanup while checking that it is still expired and still pending. A competing record-save operation must not be able to promote the same object at the same time. Use a lifecycle transition or lease that your application can enforce consistently.
Exclude active transfers and committed attachments. File modification time alone is weak evidence: a completed temporary file may be waiting for form submission, and a slow transfer may be actively appending bytes. Do not walk a directory and delete everything older than an arbitrary number of minutes without consulting the uploader's documented lifecycle.
Make the cleanup operation retryable
A cleanup run can fail halfway through. A locked file, a recycled process or a transient storage error should not leave the database claiming success when bytes are still present. Record the outcome and retry safely. Treat a file that is already absent as an expected case after verifying the selected storage key belongs to the cleanup record.
- The cleanup identity can access only the intended storage area.
- All candidate paths are derived from trusted storage metadata.
- A second cleanup run does not affect committed files.
- A final Save and cleanup racing on one object have a deterministic winner.
- Failures are visible through counters and server logs.
Test retention with short-lived synthetic uploads
In an isolated test directory, create one pending expired upload, one unexpired upload, one active transfer and one committed attachment. Run the lifecycle operation and verify the expected bytes and database state. Repeat after simulating an interrupted deletion. Use server-side scheduling appropriate to your host; do not rely on unload or beforeunload browser events to perform durable cleanup.
Monitor pending object count, oldest expiry and occupied bytes. A growing backlog can indicate a failed job or an application path that never marks uploads committed. Keep capacity management separate from the user-visible success of a single transfer.
Common questions
Can I clean up when the browser tab closes?
Use that only as an optional hint. Browser shutdown, connection loss and mobile suspension can prevent the request from arriving.
Should cleanup remove files after a fixed age even if the form is still open?
Define an explicit pending-upload expiry and communicate it. Exclude active and committed objects, and let the final Save detect an expired pending upload safely.
Related guides and working examples
Official references
Examples describe the stated framework and application workflow. Check your installed component version and hosting configuration before adapting them.