fix(requests): scope follower notifications per request and recheck server types under lock - #1653
Conversation
A series can have a completed request still waiting for the library beside a newer open request for other seasons. Follows belong to the title, so the completed request's notification went to, and cleared, follows made for the open request, and declining the open request deleted follows still waiting for the completed one. The notification now goes to the follows made before its request completed, and a decline keeps the follows a completed, not yet notified request of the title is waiting to tell. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ow lock A route save and a server save each validated the other before their transactions and rechecked only the 4K switch under the server's row lock. Two admins saving at once could leave a movie route pointing at a server that had just become a Sonarr, or one that no longer takes movies, and every request it routed would fail when sent. Both saves now recheck the server's type and media types with the row locked, and a server save does so under Standard too. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
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: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2d1103e10f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
The Suggested replacement:
Automated check: Macroscope check run agent (gpt-6-luna). No validation was performed. Posted via Macroscope — v1 validation impact |
…mpletion Two completed requests for one series can both wait for the library, and the newer can arrive first. Bounding followers only by the request's own completion time told the newer request's notification about the older request's followers too, and cleared them. A title has one open request at a time, so a request's followers are the follows made after the title's previous request completed and no later than it did. Clearing them is bounded the same way, so a profile that unfollowed and followed again during the dispatch keeps its new follow. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e329f4a6d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Bounding a request's followers by timestamps broke when a follow committed while a completion was under way: the completion's timestamp comes from the start of its transaction, so it could be earlier than the follow's, and the follow was left out of the request it had read. A follow now records the request that was open when it was made, and a request's notification, its follow cleanup and a decline all go by that request. A new request takes over the follows of a failed request, or of one its requester replaced, so a follow still survives its request failing. Existing follows go to the title's open request, or else to its latest completed request that has not been notified. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5bebde23f2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A profile following an older completed request of a series could not follow a newer request for other seasons: the key was per title, the insert kept the old row, and the title showed as followed. The backfill also gave every existing follow to the open request, even ones made for an older request. Follows are now keyed by account, profile and request, and the "following" state reads the follow on the title's open request. A new request takes over the follows of the title's failed requests before any it replaces are deleted. The backfill gives each follow the title's latest request created before it, which is the request that was open then. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d29a0a88d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…quests' follows A new request took over a failed request's follows by deleting and re-inserting them. An unfollow running at the same moment waited on the deleted row, could not see the new one, and returned while the profile still followed the new request. The follows now move with an UPDATE, which the waiting unfollow re-checks and deletes. The backfill gave a follow the title's latest request created before it even when that request was already closed by then, as when the followed request was deleted by its requester's replacement. It now takes that request only if it could still have been open, and otherwise the title's open request. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1b46795c29
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…quest-revamp-kody-review
The download-progress change pinned the SDK to its pull request commit, which was squash-merged as v0.19.0 and is no longer fetchable, so the Go jobs could not download the module. v0.19.0 has the same contents. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A follow made for a request that later failed stayed with the failed request when its replacement had already completed and was still waiting to notify, since the backfill only looked for an open request. It now gives such a follow the title's first request since the follow that still has a notification to send. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6862713237
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A completion's timestamp is taken when its transaction begins, so a follow that committed while it ran can carry a later created_at than the request's completed_at. The backfill took that as the request having closed before the follow and moved or dropped the follow. A completed request that has not notified now keeps such a follow when the title has no request created after it; a follow whose request was replaced and deleted always has that replacement after it, so the two cases stay apart. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ae723e05fb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A follow whose request was replaced and deleted, where the replacement has since failed too, was dropped: the fallback looked only at active requests. Such a follow now stays with the title's latest failed request, for the next request to take over. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Problem
Related issue: #1201
Validation tasks: reaches #1202 C3, #1204 C2, Silo-Server/silo-apple#328 C2, Silo-Server/silo-apple#329 C2, Silo-Server/silo-android#338 C2, Silo-Server/silo-android#339 C2, #1234 C1, #1235 C2, Silo-Server/silo-apple#336 C1 and Silo-Server/silo-android#346 C1 (none run yet)
Two review findings on #1632 hold up against the code.
Approach
media_request_followsgainsrequest_id, and its key becomes (account, profile, request), so a profile can follow each of a title's requests. The insert reads the open request under the share lock it already took. A request's fulfilled notification, the clear after it, and a decline or withdrawal all go by that request. Thefollowingstate reads the follow on the title's open request, and unfollowing a title removes the profile's follows on all its requests.UPDATE, so an unfollow running at the same moment waits and then removes the moved row.FOR SHARE, alongside the 4K check it already did. A server save rechecks the routes sending to it with the row heldFOR UPDATE, under Standard as well as Advanced. The service's pre-checks use the same messages.media-requests.mddescribes both rules.No API change.
The branch also pins the plugin SDK to
v0.19.0. #1649 merged intofeat/request-revamppinned to the SDK pull request's commit, which was squash-merged asv0.19.0and can no longer be fetched, so every Go job failed to download the module.v0.19.0has the same contents.Validation
go testpasses forinternal/requests/...andinternal/apiv2with DB-backed tests enabled.make lint-changedandverify-local-pathsare clean.Risks
media_request_followsby request and backfills it. The table is new in the request revamp and not on main. Rolling back returns follows to one per profile and title, keeping the earliest.Checklist
AI Disclosure
🤖 Generated with Claude Code
Note
Scope follower notifications per request and recheck server types under lock
notifyFulfilledPending) notifies and clears only the follows attached to that request. Unfollowing remains title-wide. See follows.go and notify.go.SaveRouteConditional) and integration saves (SaveIntegrationWithDefaults,UpdateIntegrationConditional) recheck this under the server row lock, closing a race where a stale route could be saved after a server changed. See routes_admin.go and routing_mode.go.Macroscope summarized ae616e0.