Files
music_library/backlog/tasks/ml-169.7 - Fix-Stream-reset-on-every-scrobble-PubSub-update.md
2026-05-25 12:52:01 +03:00

4.0 KiB

id, title, status, assignee, created_date, updated_date, labels, dependencies, references, modified_files, parent_task_id, priority, ordinal
id title status assignee created_date updated_date labels dependencies references modified_files parent_task_id priority ordinal
ML-169.7 Fix: Stream reset on every scrobble PubSub update To Do
2026-05-19 11:48 2026-05-25 09:50
perf
fix
backlog/documents/doc-27 - Phase-4-Performance-Audit-Low-Hanging-Fruit-Findings.md
lib/music_library_web/live/stats_live/index.ex
lib/music_library_web/live/scrobbled_tracks_live/index.ex
ML-169 high 28000

Description

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-583assign_scrobble_activity with reset: true
  • lib/music_library_web/live/scrobbled_tracks_live/index.ex:279handle_info(%{track_count: _count})
  • lib/music_library_web/live/scrobbled_tracks_live/index.ex:334load_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.

Acceptance Criteria

  • #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

Implementation Notes

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).