Delete the Playwright source video once it's been copied - #128
Open
a-abdellatif98 wants to merge 1 commit into
Open
Delete the Playwright source video once it's been copied#128a-abdellatif98 wants to merge 1 commit into
a-abdellatif98 wants to merge 1 commit into
Conversation
Chromium writes its own recording into record_video_dir, which we point at video_storage_dir. save_video then streams a second copy into the same directory, attaches that copy, and removes it, but nothing ever removed Playwright's original, so every check leaked one page@<hash>.webm forever. Video#save_as only copies the artifact; Video#delete is what removes the source, and Upright never called it. Delete in ensure so a failed save_as doesn't leak the source permanently, and report a failed delete rather than masking whatever save_video raised.
a-abdellatif98
force-pushed
the
fix-playwright-video-leak
branch
from
August 15, 2026 19:24
8a1bcef to
86308d8
Compare
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR ensures Playwright-recorded source videos are deleted after being copied into Upright’s storage directory, preventing unbounded growth of the configured recording directory.
Changes:
- Delete the Playwright source video in an
ensureblock after attempting to save the copied video. - Add test coverage for successful save, save failure, and delete failure reporting.
- Document the behavior change in the changelog.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| test/models/upright/playwright/video_recording_test.rb | Adds tests verifying source video deletion and error reporting behavior. |
| app/models/concerns/upright/playwright/video_recording.rb | Deletes Playwright source video after copy (even on failure) and reports delete errors. |
| CHANGELOG.md | Notes the new behavior preventing record_video_dir growth. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| self.video_artifacts ||= [] | ||
| video_artifacts << pending_video_recording.merge(path: video_path) | ||
| ensure | ||
| video&.delete rescue Rails.error.report($!) |
Comment on lines
+1
to
+13
| require "test_helper" | ||
|
|
||
| class Upright::Playwright::VideoRecordingTest < ActiveSupport::TestCase | ||
| class FakeVideo | ||
| attr_reader :source_path | ||
|
|
||
| def initialize(source_path) | ||
| @source_path = source_path | ||
| File.write(source_path, "video") | ||
| end | ||
|
|
||
| def save_as(path) = FileUtils.cp(source_path, path) | ||
| def delete = FileUtils.rm_f(source_path) |
Comment on lines
+20
to
+21
| setup do | ||
| @video_dir = Pathname.new(Dir.mktmpdir) |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
app/models/concerns/upright/playwright/video_recording.rb:52
- Using a rescue modifier here makes the control flow harder to read and relies on
$!, which is implicit/global state. Consider expanding this into an explicitbegin ... rescue => e ... end(capturing the exception as a local) and then reportinge. This is clearer and avoids any ambiguity if this line is ever refactored or wrapped by additional exception handling.
video&.delete rescue Rails.error.report($!)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #110.
Chromium writes its own recording into
record_video_dir, whichvideo_recording_optionspoints atvideo_storage_dir.save_videothen streams a second copy into that same directory viaVideo#save_as, andattach_videouploads that copy and removes it. Nothing ever removed Playwright's original, so every check leaked onepage@<hash>.webm, forever. The reporter sawstorage/playwright_videosreach 36 GB at roughly 0.4 GB/day.Video#save_asonly copies the artifact, it goes throughsaveAsStreamand leaves the source in place.Video#deleteis what removes it, and Upright never called it.The change
Hoist the video to a local and call
video&.deletein the existingensure:Deleting in
ensureis the point: ifsave_asraises, the source would otherwise be leaked permanently.The rescue is load-bearing rather than merely defensive.
Video#deletecan itself raise, since@artifact.value!re-raises when the page closed without producing frames and the channel may already be gone. Without the rescue, a failure there inensurewould replace whateversave_asraised and hide the original error. The form matches the existingpage&.close rescue Rails.error.report($!)inUpright::Playwright::Lifecycle.Scope
This fixes the primary leak, the Playwright source, which leaks once per check unconditionally.
It does not address the secondary case the issue mentions, the
<hex>.webmcopy stranded when attaching never completes.attach_videoonly removes files it successfully attaches, so a failure before or during attach still leaves that copy behind. That is a different code path and a different failure mode, so I left it out to keep this diff focused. Happy to follow up if you'd like it in the same PR.The issue also suggests writing the
save_ascopy to a tmp dir rather than intorecord_video_dir. That is a reasonable cleanup but a separate change, so it's not included here.Tests
Added
test/models/upright/playwright/video_recording_test.rb. AFakeVideomirrors the real semantics, the constructor writes the source file,save_ascopies it, anddeleteremoves the source, with the video dir pointed at aDir.mktmpdir. Three cases:video_artifactssave_asraises, the source is still cleaned updeleteraises, the error is reported andsave_videodoes not raiseAll three were written first and fail against unmodified code.
Verification
bin/rubocop: 188 files, no offenses.bin/rails test: 5 pre-existing environmental failures on my machine, 3 inplaywright_probe_test.rbbecause Chromium isn't installed locally and 2 intraceroute_probe_test.rbbecausemtr-packetcan't open raw sockets unprivileged on macOS. Both files fail identically on unmodifiedmain.I could not verify the real
Video#deleteround-trip against a live Playwright server locally, for the Chromium reason above. The unit tests cover the logic. The issue reporter states they ran this patch in production and confirmedrecord_video_dirstays empty between checks.