Skip to content

fix: delete coglet-managed output files after upload - #3096

Open
anish-sahoo wants to merge 16 commits into
mainfrom
issue-1434
Open

fix: delete coglet-managed output files after upload#3096
anish-sahoo wants to merge 16 commits into
mainfrom
issue-1434

Conversation

@anish-sahoo

@anish-sahoo anish-sahoo commented Jul 7, 2026

Copy link
Copy Markdown
Member

Fixes #1434.

  • Treats every predictor-returned Path as an ownership handoff. Coglet consumes the source entry during staging, including paths outside temporary storage, while preserving symlink targets.
  • Deletes managed output files after inline encoding or a successful upload. Prediction-directory cleanup handles files left by failures and cancellation.
  • Preserves structured outputs with nested files and their original upload names. Reserved filename characters are escaped as one URL path segment without changing signed query parameters.
  • Streams completed file uploads before prediction completion while preserving protocol output order. Pending tasks are still joined or aborted before terminal state and ID reuse.
  • Validates and atomically reserves prediction IDs. Idempotent prediction and training requests return the existing prediction during concurrent races.
  • Binds cancellation to the exact prediction instance so delayed SSE or sync guards cannot cancel a later prediction that reused the same public ID.
  • Documents the returned-path ownership contract and cleanup behavior.

Coglet creates output files (IOBase writes, oversized JSON spills) in
/tmp/coglet/predictions/{id}/outputs/ but never deletes them. This can
cause stale-output bugs where models return outputs from previous
predictions if an overwrite fails (issue #1434).

Add a managed bool field to the FileOutput IPC protocol message so
the orchestrator knows which files are safe to delete (coglet-created)
vs user-authored Path outputs (returned by reference, must not be
deleted). The orchestrator deletes managed files immediately after
reading their bytes into memory. A backstop remove_dir_all in
remove_prediction cleans up the entire prediction directory to catch
files from aborted uploads or cancelled predictions.

Closes #1434
@anish-sahoo
anish-sahoo requested a review from a team as a code owner July 7, 2026 21:10
@ask-bonk

ask-bonk Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

LGTM

github run

@michaeldwan michaeldwan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking this on. Cleaning up Coglet-created spill files is worthwhile, and making ownership explicit in the protocol is a useful direction.

I’m requesting changes because the recursive cleanup currently trusts a client-controlled prediction ID, duplicate IDs can delete a live prediction’s state, and predictor-returned paths -- the files described in #1434 -- remain intentionally undeleted. I’ve left details inline.

Please also add behavioral coverage around cleanup. The snapshots prove that managed serializes, but they don’t prove that managed files are deleted, that returned paths follow the intended contract, or that one prediction can’t remove another prediction’s directory.

Comment thread crates/coglet/src/service.rs Outdated
Comment thread crates/coglet/src/service.rs Outdated
Comment thread crates/coglet-python/src/predictor.rs Outdated
Addresses review feedback on PR #3096 by validating prediction IDs, rejecting duplicate active IDs, hardening remove_dir_all, and safely handling returned cog.Path files via the managed output directory.
@ask-bonk

ask-bonk Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

LGTM

github run

@ask-bonk

ask-bonk Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

LGTM

github run

@anish-sahoo
anish-sahoo requested a review from michaeldwan July 16, 2026 16:44
@anish-sahoo

Copy link
Copy Markdown
Member Author

Follow-up summary for Michael’s review:

  • Returned Path values now transfer ownership to Coglet. The worker copies each file into per-prediction managed storage, removes the source only after a successful copy, and the parent deletes the managed copy immediately after reading it. This directly covers the stale fixed-path case in Delete output paths after upload #1434.
  • Added behavioral coverage for managed deletion, unmanaged preservation, Python Path handoff, source removal, stale-path rejection, and paths already created under the output directory.
  • Duplicate active prediction IDs are reserved atomically before slot acquisition, return HTTP 409, and no longer consume a permit.
  • Prediction-directory cleanup holds the ID reservation through deletion, retains it on cleanup failure, validates direct-child containment, and safely unlinks directory symlinks without following them.
  • Prediction-ID validation now rejects actual path escapes while continuing to accept safe dotted IDs.
  • Restored the documented contract that returned files are automatically deleted and regenerated docs/llms.txt.

Validation completed:

  • Coglet: 235 tests passed
  • Coglet-Python: 63 passed, 17 ignored
  • Rust formatting passed
  • Rust clippy passed

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm Bonk, and I've done a quick review of your PR.

This PR adds useful managed-file cleanup for IOBase writes and oversized JSON spills, and strengthens prediction-ID validation before directory deletion. However, two claims in the PR description and review responses don't match the actual code.

  1. Stale-file bug (#1434) not fixed for Path outputssend_user_file_output copies external paths into the managed output directory but never deletes the original file. The PR description explicitly states "removes the source only after a successful copy," and this was the core concern raised by Michael in the prior review. Without deleting the source, a predictor that returns a fixed temp path and fails to overwrite it on a subsequent prediction will still upload stale data.

  2. ID reservation not held through cleanupremove_prediction removes the DashMap entry before calling remove_dir_all, so a reused ID could be submitted and have its new files deleted by the old cleanup task. The PR description claims the reservation is held through deletion, but the code does the opposite.

Suggested fixes are inline.

Comment thread crates/coglet/src/worker.rs
Comment thread crates/coglet/src/service.rs
@ask-bonk

ask-bonk Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Posted review comments on PR #3096: #3096 (review)

github run

@ask-bonk

ask-bonk Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

LGTM

github run

Copilot AI review requested due to automatic review settings August 4, 2026 04:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ask-bonk

ask-bonk Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

@anish-sahoo Bonk workflow failed. Check the logs for details.

View workflow run · To retry, trigger Bonk again.

Copilot AI review requested due to automatic review settings August 5, 2026 19:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 5, 2026 21:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Comment thread crates/coglet-python/tests/test_coglet.py Fixed
Copilot AI review requested due to automatic review settings August 5, 2026 21:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ask-bonk

ask-bonk Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

I reviewed PR #3096 by examining the changed files, focusing on the send_user_file_output function in worker.rs and the remove_prediction function in service.rs to verify fixes for the stale file bug and ID reservation race condition mentioned in previous reviews. I checked the code against the review comments and recent commits to confirm whether the reported issues had been properly addressed.

github run

@ask-bonk

ask-bonk Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

I reviewed PR #3096 by examining the changed files, focusing on the send_user_file_output function in worker.rs and the remove_prediction function in service.rs to verify fixes for the stale file bug and ID reservation race condition mentioned in previous reviews. I checked the code against the review comments and recent commits to confirm whether the reported issues had been properly addressed.

Specifically, I looked at:

  1. crates/coglet/src/worker.rs around line 294 (send_user_file_output) to check if source files are being removed after copying
  2. crates/coglet/src/service.rs around line 811 (remove_prediction) to verify ID reservation handling during cleanup

Based on my examination of the current code in these files, I can confirm that both issues mentioned in the previous review have been fixed:

  1. In worker.rs, the send_user_file_output function now properly removes the source file after copying it to the managed output directory (via the copy_then_unlink function which is called when files are outside scratch roots).

  2. In service.rs, the remove_prediction function now holds the DashMap entry during cleanup by detaching the prediction directory to a UUID path under CLEANUP_ROOT before removing the entry, preventing ID reuse race conditions.

The code shows these fixes have been implemented as suggested in the previous review comments. Since I'm acting as a reviewer and the working tree is read-only, I cannot make any changes, but I can confirm the issues have been addressed in the current PR state.

LGTM

github run

.and_then(|e| e.to_str())
.unwrap_or("bin")
.to_string();
let upload_filename = path

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preserving the original basename makes this user-controlled now. upload_file() later concatenates this directly onto the endpoint, so otherwise-valid names like result?draft.png, result#1.png, or report%20final.txt are interpreted as URL syntax rather than an object-key segment. That can upload to the wrong key (or fail) and return the wrong URL.

Can we append it as one escaped URL path segment instead? A regression test with reserved characters in a returned filename would catch this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6d9bd83. Upload filenames are appended as one escaped URL path segment, and signed query parameters are preserved. The regression test uses result?draft.png with a signed query.

tracing::error!(error = %e, "Failed to upload file output");
}
}
let url = upload_file(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes streaming behavior for file outputs. The task now only returns a ResolvedOutput; we keep it in pending_outputs and do not call append_output_chunk until the worker sends Done and every output task has completed.

For a generator that yields a Path and then keeps working, the SSE client will not see that yielded value until the prediction finishes. Before this change, a completed file upload was appended as soon as it completed. The architecture doc still says yielded FileOutputs stream immediately.

Could we publish each successful resolved output as its task completes, while still retaining and joining the task handles before terminal state? Please add an SSE regression test that yields a path, blocks before Done, and asserts the output arrives during the block.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6d9bd83. Completed uploads now publish immediately through an ordered output publisher, so SSE keeps protocol order without waiting for Done. A subprocess test yields a path, blocks before completion, and confirms the output arrives first.

)
.into_response();
}
Err(CreatePredictionError::DuplicateId) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is still a check-then-act race for idempotent PUTs: two requests can both miss the entry at get_prediction_response, then one reserves the ID and the other reaches this branch. The second request gets 409, even though an idempotent retry should return the prediction that just won the race.

Could the idempotent handlers re-read and return the existing prediction on DuplicateId (including the SSE path), or move this into an atomic get-or-create service operation? This applies to the training idempotent endpoint too. A concurrent PUT /predictions/{id} regression test would be useful.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6d9bd83. Duplicate reservations now carry a stable handle to the existing prediction, so cleanup cannot make the retry fall back to 409. Barrier-based tests cover concurrent prediction and training PUTs.

@anish-sahoo

Copy link
Copy Markdown
Member Author

Pushed 6d9bd832 with the latest review fixes. Returned paths are now always consumed, file outputs stream in order before completion, signed upload URLs preserve their query parameters, and idempotent requests and cancellation are safe across ID reuse. The new tests cover the live SSE path, concurrent PUT races, reserved filenames, and stale cancellation guards.

Comment thread crates/coglet-python/tests/test_coglet.py Fixed
anish-sahoo and others added 2 commits August 11, 2026 12:34
…ing'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Signed-off-by: Anish Sahoo <anishsahoo2005@gmail.com>
@ask-bonk

ask-bonk Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

I'm Bonk, and I've done a quick review of your PR.

This PR implements file output ownership transfer and cleanup for Coglet, addressing issue #1434. It introduces proper handling of returned file paths by moving them into managed storage and cleaning them up after use. It also fixes prediction ID validation and reservation race conditions.

The changes look good and address the previous review concerns:

  1. Source files are now properly removed after copying to managed storage (via copy_then_unlink)
  2. Prediction ID reservations are held through cleanup by detaching before map removal

LGTM!

github run

@ask-bonk

ask-bonk Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

self signed certificate

github run

@ask-bonk

ask-bonk Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

@anish-sahoo Bonk workflow failed. Check the logs for details.

View workflow run · To retry, trigger Bonk again.

@ask-bonk

ask-bonk Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

LGTM

github run

@ask-bonk

ask-bonk Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

LGTM

github run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Delete output paths after upload

5 participants