Repository navigation
Release every lock on every exit path - #74
Merged
Merged
Conversation
…exit path Every sync.lock in these domains is now followed by a deferred unlock, so an error can't leave the lock held until restart. Where work carried on after the unlock, the locked part moved into its own function, so each lock still covers the same steps and nested locks keep their order. The bans file helpers take the lock in their callers instead of handing it from lockBans to saveAndUnlockBans.
Blocking a URL appended it to a copy of the policy's list and never wrote the list back, so the block was never saved. The list is now written back before the policy is saved.
Every remaining lock in these domains is now followed by a deferred unlock, so an error can't leave it held until restart. Where work carried on after the unlock, the locked part moved into its own function, so each lock still covers the same steps: pull numbering, branch changes, pull comment counts and fast-forward merges, the backpack (still taking the quota lock before the backpack lock), extension records, staged assets, the storage ledger queues and the R2 inventory. The remix and reaction wrappers use runLocked. Tests make a locked step throw in pulls, the backpack and the upload quota, and check the lock can be taken again.
Adds pull comments, commit co-author credits, branch renames and deletes, reactions, staged assets, the backpack and the admin extension policies, with random comment and backpack ids normalized.
Renaming and purging a user rewrote the bans file without the lock the ban and sync code take, so a concurrent ban could be lost. Nothing else is locked while the bans lock is held, so the order can't invert.
Blocking or unblocking a URL reads, edits and saves the policy file under one lock, so two admins changing it at once can't lose a change.
The remixer's project limit and storage allowance come from their plan, which can mean asking Rotur. They are now looked up before the parent project's save lock is taken and passed to forkProjectFor, so a slow Rotur doesn't hold up saves and history writes of the original.
Mistium
force-pushed
the
fix-remaining-locks
branch
from
November 1, 2026 09:32
7b8cae4 to
c254b14
Compare
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.
Stacked on the save-bug fixes (fix-project-save-bugs).
About 100 more places took a lock and unlocked it by hand on each return path, so any thrown error left the lock held until the server restarted. They are spread across projects, git, history, storage, community, classroom, admin, games, Rotur payments and webhooks, and auth. Every one now uses
runLockedorsync.lockwith a deferred unlock.*Lockedfunction, so it covers exactly what it covered before.Also fixed:
banslock.Verification
osl testpasses 59. New tests make a locked step throw and then take the lock again, for pull numbering, comment counts, merges, branch changes, the nested backpack add and quota. They fail without the defers.There is no visible change.