70 lines
4.0 KiB
Markdown
70 lines
4.0 KiB
Markdown
---
|
|
id: ML-169.7
|
|
title: "Fix: Stream reset on every scrobble PubSub update"
|
|
status: To Do
|
|
assignee: []
|
|
created_date: "2026-05-19 11:48"
|
|
updated_date: "2026-05-25 09:50"
|
|
labels:
|
|
- perf
|
|
- fix
|
|
dependencies: []
|
|
references:
|
|
- >-
|
|
backlog/documents/doc-27 -
|
|
Phase-4-Performance-Audit-Low-Hanging-Fruit-Findings.md
|
|
modified_files:
|
|
- lib/music_library_web/live/stats_live/index.ex
|
|
- lib/music_library_web/live/scrobbled_tracks_live/index.ex
|
|
parent_task_id: ML-169
|
|
priority: high
|
|
ordinal: 28000
|
|
---
|
|
|
|
## Description
|
|
|
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
|
|
|
Fix performance issue where every scrobble batch (cron: every 5 minutes) triggers a PubSub message that causes StatsLive.Index and ScrobbledTracksLive.Index to reload their entire stream with `reset: true`.
|
|
|
|
## Problem
|
|
|
|
Every scrobble batch triggers a `"listening_stats:update"` PubSub message which causes:
|
|
|
|
- **StatsLive.Index**: Re-executes `recent_activity` (expensive 4-correlated-subquery query) + `scrobble_count`, then resets the `:recent_tracks` and `:recent_albums` streams
|
|
- **ScrobbledTracksLive.Index**: Re-executes the full paginated list query and resets the `:tracks` stream
|
|
|
|
This fires every 5 minutes on ALL connected clients, even idle ones.
|
|
|
|
## Files
|
|
|
|
- `lib/music_library_web/live/stats_live/index.ex:576-583` — `assign_scrobble_activity` with `reset: true`
|
|
- `lib/music_library_web/live/scrobbled_tracks_live/index.ex:279` — `handle_info(%{track_count: _count})`
|
|
- `lib/music_library_web/live/scrobbled_tracks_live/index.ex:334` — `load_and_assign_tracks` with `reset: true`
|
|
|
|
## Fix
|
|
|
|
- **StatsLive**: Use `stream_insert` for new tracks instead of `reset: true`. Keep a cursor (e.g., max `scrobbled_at_uts`) to only insert genuinely new tracks.
|
|
- **ScrobbledTracksLive**: Use `stream_insert` for new tracks only if they match the current search/filter. Otherwise, show a "new scrobbles" badge that refreshes on user click.
|
|
- Consider debouncing or batching the updates to avoid per-track insert thrash.
|
|
<!-- SECTION:DESCRIPTION:END -->
|
|
|
|
## Acceptance Criteria
|
|
|
|
<!-- AC:BEGIN -->
|
|
|
|
- [ ] #1 StatsLive no longer performs full stream reset on scrobble updates
|
|
- [ ] #2 Only new tracks are inserted into streams
|
|
- [ ] #3 ScrobbledTracksLive no longer performs full stream reset on scrobble updates
|
|
- [ ] #4 Existing stream ordering is preserved after insert
|
|
- [ ] #5 No duplicate tracks appear in streams
|
|
<!-- AC:END -->
|
|
|
|
## Implementation Notes
|
|
|
|
<!-- SECTION:NOTES:BEGIN -->
|
|
|
|
Audit findings (2026-05-25): ML-169.7 is valid and still unresolved. Evidence: `ListeningStats.update/1` broadcasts `%{track_count: count}` on `"listening_stats:update"` (`lib/music_library/listening_stats.ex:67`), and prod cron runs `RefreshScrobbles` every 5 minutes (`config/prod.exs:65-66`). `StatsLive.Index` handles non-zero updates by calling `assign_scrobble_activity/1`, which re-runs `ListeningStats.recent_activity/1` and `ListeningStats.scrobble_count/0`, then resets `:recent_tracks` and `:recent_albums` (`lib/music_library_web/live/stats_live/index.ex:316-321`, `654-671`). `ScrobbledTracksLive.Index` handles non-zero updates by calling `load_and_assign_tracks/2`, which re-runs `ListeningStats.list_tracks/1` and resets `:tracks` (`lib/music_library_web/live/scrobbled_tracks_live/index.ex:280-282`, `347-355`). Nuance: both LiveViews no-op for `%{track_count: 0}`, so the exact issue is every non-empty scrobble PubSub update, not literally every cron run. Implementation caveats: PubSub currently contains only count, not inserted track IDs; Stats `recent_albums` is deduped from tracks so naive inserts can duplicate albums; prepending multiple stream items must preserve order; ScrobbledTracks should likely insert only for page 1 + `:scrobbled_at` order + matching filter, otherwise show a refresh/new-scrobbles badge. Test coverage gap: current LiveView tests do not exercise this PubSub stream-reset path. Validation during audit: `mix test test/music_library_web/live/stats_live/index_test.exs test/music_library_web/live/scrobbled_tracks_live/index_test.exs` passed (23 tests).
|
|
|
|
<!-- SECTION:NOTES:END -->
|