Skip to content

fix: serialize export session operations on a lifecycle lock - #20

Merged
cchacs merged 2 commits into
mainfrom
pullfrog/18-serialize-session-lifecycle
Oct 11, 2026
Merged

cchacs merged 2 commits into
mainfrom
pullfrog/18-serialize-session-lifecycle

Conversation

@pullfrog

@pullfrog pullfrog Bot commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

Closes #18.

An export session's work directory was only guarded by the video-append
append_lock. Mux did not wait for in-flight video/audio uploads and treated
an existing audio.bin as complete; cancellation and the TTL/size sweep could
remove the directory (and mux's own post-success cleanup) while an upload was
still writing; and multiple mux requests could all pass the audio-resolution
step that runs before the session is popped, then race the same work dir.
Reproduced with a stubbed FFmpeg boundary: a mux invoked FFmpeg and returned
FileResponse while a video append was still streaming, so FFmpeg read a
partial elementary stream and the session was consumed before the upload
finished.

What changed

Every operation that touches a session's work dir now holds that session's
single lifecycle lock (state["lock"], replacing the append-only append_lock):

  • Video and audio uploads hold it for their whole stream, so a mux can only
    start once all uploads are finalized — FFmpeg never reads partial media.
  • Mux holds it across audio resolution and the FFmpeg run, which makes it
    a single mux owner: a second concurrent mux waits, then sees the consumed
    session and gets a 404. It also keeps cancel/eviction away from the files
    while FFmpeg uses them.
  • Cancel and the sweep (_drop_session/_sweep_sessions) take the lock
    before popping and rmtree, so cleanup never deletes files an operation
    still has open. The sweep skips an in-use session rather than blocking.
  • A waiter re-checks sessions.get(session_id) is state under the lock, so an
    operation that lost the race against a consume/evict returns 404 instead of
    acting on a stale reference.
  • Newly hardened (same theme): a mux cancelled or disconnected mid-FFmpeg now
    removes its work dir instead of leaking it — the response's background
    cleanup is only registered on success.

Tests

Six new barrier-based tests, each proven to fail without its guard by running
the suite against a mutated routes.py:

  • test_mux_waits_for_an_in_flight_upload_before_running_ffmpeg — mux is parked
    on the lock while the upload is mid-body; FFmpeg sees the complete stream.
  • test_mux_waits_for_an_in_flight_audio_upload — a half-written audio.bin
    is never muxed as a complete mix.
  • test_two_concurrent_muxes_consume_the_session_once — one FFmpeg invocation,
    statuses [200, 404], even with both muxes overlapping audio resolution.
  • test_cancel_waits_for_an_active_upload_before_removing_the_work_dir — cancel
    blocks until the upload finishes, then removes the dir.
  • test_eviction_skips_a_session_mid_operation — the sweep leaves a locked
    session's files alone and collects it once idle.
  • test_cancelled_mux_removes_the_work_dir — a cancelled mux leaks nothing.

Full suite: 43 passed. Version bumped to 0.3.3; CHANGELOG.md and
CLAUDE.md updated.

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

@pullfrog
pullfrog Bot requested a review from cchacs October 11, 2026 02:45
@pullfrog

pullfrog Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor Author

Checked out PR #20, the branch already contains the fix to serialize export session operations. Fetched check suite logs (no failed workflow runs found for check_suite 103244797119). Ran full CI checks locally: manifest validation, JS syntax, JS tests, print/traceback check, installed test deps, and route tests all pass (43 passed). No local changes needed; branch is clean. No push required.

Task list (6/7 completed)
  • checkout_pr for PR fix: serialize export session operations on a lifecycle lock #20
  • get_check_suite_logs for check_suite 103244797119
  • investigate logs and CI to understand failure
  • verify failure is caused by this PR and diagnose root cause
  • reproduce locally with exact CI commands and fix
  • verify fix, commit, push to existing PR
  • report progress with summary

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

@kilo-code-bot

kilo-code-bot Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • routes.py
Previous Review Summary (commit 7623b2d)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 7623b2d)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (5 files)
  • CHANGELOG.md
  • CLAUDE.md
  • plugin.json
  • routes.py
  • tests/test_routes.py

Reviewed by free · Input: 137.4K · Output: 8.2K · Cached: 427.7K

cchacs
cchacs previously approved these changes Oct 11, 2026
@cchacs
cchacs merged commit b99d42a into main Oct 11, 2026
4 checks passed
@cchacs
cchacs deleted the pullfrog/18-serialize-session-lifecycle branch October 11, 2026 10:03
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.

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

1 participant