fix: swap the vendor directory with renames instead of a delete and a move - #5034
Open
ernestdefoe wants to merge 1 commit into
Open
ernestdefoe wants to merge 1 commit into
ernestdefoe wants to merge 1 commit into
Conversation
… move Safe mode builds the new dependency tree in temp-vendor and then swaps it in by deleting vendor and moving temp-vendor over it. Between those two steps the forum has no vendor directory, for as long as it takes to delete and then move several hundred megabytes of packages. That happens at the very end of a job that can be killed — a Horizon worker timeout, a memory limit, a container restart. A process that dies inside the window leaves the site with no vendor directory at all and a temp-vendor nobody thinks to look for, and the forum stops booting until somebody completes the move by hand. Renaming twice closes the window: it is effectively instantaneous on the same filesystem, and the working tree survives under vendor-previous until the new one is in place. If the second rename fails, the old tree is put back and the failure is reported on the task, so an admin sees a failed update rather than a forum that has stopped responding. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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
Safe mode can leave a forum with no
vendor/directory at all, and the site stops booting until somebody finishes the move by hand.Changes
ComposerAdapter::run()builds the new dependency tree intemp-vendorand then swaps it in like this:Between those two statements the forum has no
vendor/, for as long as it takes to delete and then move several hundred megabytes of packages. That is not a small window on a real install, and it is the very last thing a long-running job does — a job that can be killed by a Horizon worker timeout, a memory limit, or a container restart.A process that dies inside the window leaves
vendor/gone andtemp-vendor/orphaned. The forum returns 500s, and nothing in the admin explains why: the task row still saysrunning, because the job never reached the code that would have marked it failed.I hit this on a live forum while debugging an unrelated update failure. Recovery was
mv temp-vendor vendorfollowed bycomposer install, which is fine if you have shell access — but this extension exists largely for people who do not.This changes the swap to two renames:
Renames are effectively instantaneous on the same filesystem, so the window shrinks from "however long it takes to move hundreds of megabytes" to a single syscall. The working tree also survives under
vendor-previousuntil the new one is in place, so an interrupted run leaves something recoverable rather than nothing.If the second rename fails, the old tree is moved back and a
RuntimeExceptionis thrown.ComposerCommandJobalready catchesThrowableand records it on the task, so the admin sees a failed update instead of a forum that has stopped responding.No behaviour changes on the success path.
Reviewer notes
Filesystem::moveDirectory()returnsfalsewhen the underlying@rename()fails, which is what the restore path keys off.vendor-previousis removed at the end of a successful swap, and any leftover from an interrupted earlier run is removed before the next one starts.