Skip to content

Serialize mux, upload, cancellation, and eviction across an export session #18

Closed

Description

@cchacs

Audited main at a7bad12. Existing tests pass: 33 Python, 9 JavaScript.

The append_lock protects video appends only. mux_session does not wait for active video/audio uploads, and treats an existing audio.bin as complete. Cancellation and session eviction can also remove a working directory during an operation. Multiple mux requests can retain the same session before its eventual pop, notably while resolving host audio.

Reproduced with a video request yielding a 16 KiB chunk, then blocked before its final chunk. A concurrent mux request invoked the FFmpeg boundary and returned FileResponse while the upload was still active. Thus FFmpeg can read incomplete media and the session is consumed before the upload finishes; response cleanup can then remove its files. This reproducer used a stubbed FFmpeg boundary to observe invocation deterministically.

Introduce a session lifecycle lock/state shared by uploads, mux, cancel, and eviction. Only mux finalized media, permit a single mux owner, and keep cleanup from removing files still in use. Add barrier-based tests for upload-versus-mux, duplicate mux, and cancellation/eviction during active operations.

Activity

  1. pullfrog commented on Oct 11, 2026

    @pullfrog
    Contributor
  2. pullfrog commented on Oct 11, 2026

    @pullfrog
    Contributor

    Built issue #18. PR: #20

    routes.py now serializes every operation that touches an export session's work dir behind a single per-session lifecycle lock (state["lock"], replacing the video-append-only append_lock): uploads hold it for their whole stream, mux holds it across audio resolution and the FFmpeg run (making it the single mux owner), and cancel/eviction take it before removing files. This closes the reproduced race where a mux invoked FFmpeg on a partial stream and consumed the session out from under an active upload, plus duplicate-mux races during host-audio resolution.

    Added six barrier-based tests, each proven to fail against a mutated routes.py: upload-versus-mux for both video and audio, duplicate mux (one FFmpeg invocation, [200, 404]), cancel and eviction during an active upload, and cancellation mid-mux (work dir no longer leaked). Full suite: 43 passed. Bumped plugin.json to 0.3.3 and updated CHANGELOG/CLAUDE.md.

    Task list (7/7 completed)
    • Read issue Serialize mux, upload, cancellation, and eviction across an export session #18 discussion and audit routes.py session lifecycle
    • Design session lifecycle lock shared by uploads/mux/cancel/eviction
    • Implement lifecycle serialization in routes.py
    • Add barrier-based tests (upload-vs-mux, duplicate mux, cancel/evict during op)
    • Run full pytest suite and verify baseline/failing behavior
    • Update CHANGELOG, plugin.json version, CLAUDE.md
    • Self-review diff via reviewfrog, commit, push, open PR

    Pullfrog  | View workflow run | via Pullfrog | Using big-pickle (free) | 𝕏

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions