fix(requests): serialize requests for the same title - #3380
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThe request flow now applies a media-keyed lock inside the existing user lock. Tests cover concurrent movie requests and overlapping TV season requests across users. ChangesMedia request concurrency
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
6ff527b to
1c091ce
Compare
There was a problem hiding this comment.
Pull request overview
This PR addresses cross-user concurrency issues in media requesting by adding an additional lock keyed by media identity, ensuring that “check/create/save” request flows for the same title are serialized even when initiated by different users.
Changes:
- Introduces a new
mediaLockAsyncLockkeyed by media type/id/4K to serialize requests per media. - Wraps
MediaRequest.request()with a nested media-based lock inside the existing per-user request lock. - Extends
MediaRequesttests with cross-user concurrent-duplicate and overlapping-season scenarios.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| server/utils/requestLock.ts | Exports a new mediaLock to support per-media serialization. |
| server/entity/MediaRequest.ts | Nests a per-media lock inside the existing per-user lock when creating requests. |
| server/entity/MediaRequest.test.ts | Adds test coverage for cross-user concurrency cases (duplicate media + overlapping seasons). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This comment was marked as outdated.
This comment was marked as outdated.
1c091ce to
3931ba3
Compare
This comment was marked as outdated.
This comment was marked as outdated.
3931ba3 to
7744584
Compare
Duplicates and overlapping seasons are already rejected, but both checks run well before the insert, so two users asking for the same title at the same moment both got through. Creation now takes a second lock keyed on the title inside the per-user one, always in that order so the two cannot deadlock. is4k is normalized at the same time. It is optional, and an undefined one binds as null in the duplicate query, so an API caller that omitted it could request the same title repeatedly.
7744584 to
498d920
Compare
Description
Duplicate requests are already rejected and seasons another request holds are already filtered out, but both checks run well before the insert, and nothing stops a second request for the same title passing them in between. Two users asking for the same movie at the same moment both got a request, and two users asking for overlapping seasons both got the season.
Creation now takes a second lock keyed on the title, inside the per-user one. The user lock is always the outer one so the two can never be taken in opposite orders.
Unlike the per-user lock, which only ever blocks somebody racing themselves, this makes unrelated users requesting the same title wait for each other, and on auto approve that wait covers the subscriber's Radarr and Sonarr work. It is also not a quota bypass being fixed, since every user is charged correctly for what they asked for, so what this removes is duplicate rows and double-booked seasons rather than a limit anyone could exceed.
This depends on the per-user lock PR below it, where the first lock lives.
How Has This Been Tested?
Screenshots / Logs (if applicable)
Checklist:
pnpm buildpnpm i18n:extractSummary by CodeRabbit