fix(collections): suppress rule re-add of items the handler just processed#2837
Merged
Conversation
…essed Track the mediaServerIds CollectionHandler.handleMedia processes per collection in a small in-memory service. RuleExecutorService.handleCollection consults it before computing mediaToAdd so the comparator pass that runs seconds after the handler doesn't re-add the same item — which produced a confusing "Media Removed" + "Media Added" notification pair for any rule keyed on conditions (watched / lastViewedAt) that don't change after the arr action. State clears via the existing Collection_Deleted event.
The suppression set was only cleared on Collection_Deleted, so once an item was handled it stayed suppressed for the lifetime of the process. For unmonitor / quality-change actions where the file remains on disk, that meant a legitimate later re-match would never re-add the item. Clear the per-collection set right after the rule executor consults it so the suppression blocks exactly the immediate echo. Update JSDoc and inline comments to match. Add a regression test that runs two passes: the first suppresses, the second re-adds.
maintainerr-automation Bot
added a commit
that referenced
this pull request
May 6, 2026
* fix(app): correct version comparison for multi-digit segments (#2838) * fix(app): correct version comparison for multi-digit segments Closes #2835 * refactor(app): drop regex prefix trim per AGENTS.md string-handling rule * build(deps-dev): bump postcss from 8.5.10 to 8.5.11 (#2839) Bumps [postcss](https://github.com/postcss/postcss) from 8.5.10 to 8.5.11. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](postcss/postcss@8.5.10...8.5.11) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.11 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump yaml from 2.8.3 to 2.8.4 (#2840) Bumps [yaml](https://github.com/eemeli/yaml) from 2.8.3 to 2.8.4. - [Release notes](https://github.com/eemeli/yaml/releases) - [Commits](eemeli/yaml@v2.8.3...v2.8.4) --- updated-dependencies: - dependency-name: yaml dependency-version: 2.8.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @typescript-eslint/eslint-plugin (#2843) Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.59.0 to 8.59.2. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.2/packages/eslint-plugin) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.59.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump react-hook-form from 7.74.0 to 7.75.0 (#2844) Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.74.0 to 7.75.0. - [Release notes](https://github.com/react-hook-form/react-hook-form/releases) - [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md) - [Commits](react-hook-form/react-hook-form@v7.74.0...v7.75.0) --- updated-dependencies: - dependency-name: react-hook-form dependency-version: 7.75.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump @typescript-eslint/parser from 8.59.1 to 8.59.2 (#2845) Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.59.1 to 8.59.2. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.2/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/parser" dependency-version: 8.59.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump axios from 1.15.2 to 1.16.0 (#2842) Bumps [axios](https://github.com/axios/axios) from 1.15.2 to 1.16.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](axios/axios@v1.15.2...v1.16.0) --- updated-dependencies: - dependency-name: axios dependency-version: 1.16.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps-dev): bump postcss from 8.5.13 to 8.5.14 (#2849) Bumps [postcss](https://github.com/postcss/postcss) from 8.5.13 to 8.5.14. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](postcss/postcss@8.5.13...8.5.14) --- updated-dependencies: - dependency-name: postcss dependency-version: 8.5.14 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * build(deps): bump react-router-dom from 7.14.2 to 7.15.0 (#2847) Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 7.14.2 to 7.15.0. - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.15.0/packages/react-router-dom) --- updated-dependencies: - dependency-name: react-router-dom dependency-version: 7.15.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix(storage-metrics): deduplicate reclaimable bytes; add cleanup byte counters (#2833) * fix(collections): suppress rule re-add of items the handler just processed (#2837) * fix(collections): suppress rule re-add of items the handler just processed Track the mediaServerIds CollectionHandler.handleMedia processes per collection in a small in-memory service. RuleExecutorService.handleCollection consults it before computing mediaToAdd so the comparator pass that runs seconds after the handler doesn't re-add the same item — which produced a confusing "Media Removed" + "Media Added" notification pair for any rule keyed on conditions (watched / lastViewedAt) that don't change after the arr action. State clears via the existing Collection_Deleted event. * fix(collections): consume recently-handled marks each rule pass The suppression set was only cleared on Collection_Deleted, so once an item was handled it stayed suppressed for the lifetime of the process. For unmonitor / quality-change actions where the file remains on disk, that meant a legitimate later re-match would never re-add the item. Clear the per-collection set right after the rule executor consults it so the suppression blocks exactly the immediate echo. Update JSDoc and inline comments to match. Add a regression test that runs two passes: the first suppresses, the second re-adds. --------- Co-authored-by: Kristian Matthews-Kennington <kristian@matthews-kennington.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: maintainerr-automation[bot] <261505141+maintainerr-automation[bot]@users.noreply.github.com> Co-authored-by: enoch85 <mailto@danielhansson.nu> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kristian Matthews-Kennington <kristian@matthews-kennington.com>
Contributor
|
🎉 This PR is included in version 3.10.2 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
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
The collection handler runs an arr/Plex/Jellyfin action and removes the item from the collection. Seconds later the rule executor re-evaluates the same conditions; rule inputs like
Jellyfin.isWatchedandJellyfin.lastViewedAtstay true after the action, so the item is re-added — and the user gets aMedia Removednotification immediately followed byMedia Addedfor the same title.This adds a small per-collection
RecentlyHandledMediaServicethatCollectionHandler.handleMedia()writes to on success andRuleExecutorService.handleCollection()consults before adding. Both code paths into the handler (the cronCollectionWorkerServiceand the manualPOST /media/handleendpoint) feed the same set, so there is one writer, one reader, and no per-call-site bookkeeping.The rule executor consumes the marks: it reads them while building its add list, then clears the per-collection set in the same pass. The suppression therefore blocks exactly the immediate echo — a later legitimate re-match (e.g. an unmonitored file becoming watched again months later) gets re-added normally and the user sees the expected notification cycle. Marks are also cleared on
Collection_Deleted.No upstream data is touched (Plex/Jellyfin playstate is left alone), no schema changes, no migrations.