Repository navigation
fix(settings): absorb the first-request browser settings create race - #1000
Merged
Merged
Conversation
A new visitor's first page load and its API calls arrive together on one fresh session. Each looked the browser settings row up, missed, and inserted; the loser hit unique_settingsbrowser_session and answered 500. The browser row, its filters and its last route are now created in one atomic block, so a loser rolls back cleanly and no request sees a row without its related rows. On IntegrityError the lookups run again and the winner's row is used; with no row found the error is re-raised. The reader path already absorbed the same race through get_or_create. Co-Authored-By: Claude Opus 5.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.
Summary
A new visitor's first page load and its API calls arrive together on one fresh session. Each request looked up the session's browser settings row, missed, and inserted one; the loser hit
unique_settingsbrowser_sessionand answered 500:Seen on a fresh database's first load of
/(FrontendView→get_last_route→_load_browser_settings_data). The reader settings path already absorbed the same race throughget_or_create; the browser path did a plaincreate.Fix (
codex/views/settings.py)transaction.atomic()block, so a losing insert rolls back cleanly and no concurrent request can see a row without its related rows.IntegrityError,_get_or_create_settingsruns the lookups again and uses the winner's row. If it still finds none, the original error is re-raised._find_settingsso the retry reuses them.Tests
tests/test_settings_create_race.pyreproduces the window the way the existing reader-race test does: the lookups miss once while the winner's row already exists. It covers an anonymous session, a logged-in user, and a realIntegrityErrorstill raising. Without the fix the two race tests fail with the exact error above.make lint,make tyandmake testpass (1745 passed). Real concurrent requests against a running server were not reproduced; the test simulates the timing.🤖 Generated with Claude Code