Files
sure/app/models/balance_sheet/sync_status_monitor.rb
T
Juan José MataandClaude 4d1d33f91d perf: memoize Family#balance_sheet and sync status lookups per request (#2553)
Family#balance_sheet built a new BalanceSheet on every call. The
application layout renders the account sidebar twice per page (desktop
+ mobile) with three tab panels each, and each panel asks the family
for its balance sheet - so the account, sync-status and exchange-rate
queries behind it ran up to six times per request.

- Memoize Family#balance_sheet per user id (Current.family is the same
  instance for the whole request, and jobs/controllers use short-lived
  Family objects, so staleness is not a concern).
- Memoize BalanceSheet::SyncStatusMonitor#syncing_account_ids in the
  instance: it is called once per account row, and each call was a
  Rails.cache round-trip (or a full re-query with the test null store).

Measured on the test suite probes: ReportsController#index view time
230ms -> 155ms, AccountsController#show 299ms -> 233ms.


Claude-Session: https://claude.ai/code/session_01RpZe2ajeGkPRRBHfaJTfUB

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-22 08:25:02 +02:00

36 lines
940 B
Ruby

class BalanceSheet::SyncStatusMonitor
def initialize(family)
@family = family
end
def syncing?
syncing_account_ids.any?
end
def account_syncing?(account)
syncing_account_ids.include?(account.id)
end
private
attr_reader :family
def syncing_account_ids
@syncing_account_ids ||= Rails.cache.fetch(cache_key) do
Sync.visible
.where(syncable_type: "Account", syncable_id: family.accounts.visible.pluck(:id))
.pluck(:syncable_id)
.to_set
end
end
# We re-fetch the set of syncing IDs any time a sync that belongs to the family is started or completed.
# This ensures we're always fetching the latest sync statuses without re-querying on every page load in idle times (no syncs happening).
def cache_key
[
"balance_sheet_sync_status",
family.id,
family.latest_sync_activity_at
].join("_")
end
end