perf: batch statistics queries and cache meeting sub-queries#192
perf: batch statistics queries and cache meeting sub-queries#192
Conversation
Greptile OverviewGreptile SummaryThis PR implements significant performance improvements through query batching and granular caching of meeting data sub-queries. Key Changes:
Architecture:
Issues Found:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant API as API Route
participant Cache as getMeetingDataCached
participant Core as getMeetingDataCore
participant DB as Database
participant UC as unstable_cache
Client->>API: GET /api/cities/{cityId}/meetings/{meetingId}
API->>Core: getMeetingDataCore(cityId, meetingId)
Note over Core: Fetch meeting & transcript<br/>(NOT cached - auth + size)
Core->>DB: getCouncilMeeting()
DB-->>Core: meeting
Core->>DB: getTranscript()
DB-->>Core: transcript
Note over Core: Cached sub-queries via createCache()
Core->>UC: city cache (unstable_cache)
alt Cache HIT
UC-->>Core: cached city
else Cache MISS
UC->>DB: getCity()
DB-->>UC: city
UC-->>Core: city (cached)
end
Core->>UC: people cache
UC-->>Core: people (HIT or MISS)
Core->>UC: parties cache
UC-->>Core: parties (HIT or MISS)
Core->>UC: subjects cache
UC-->>Core: subjects (HIT or MISS)
Core->>UC: taskStatus cache
UC-->>Core: taskStatus (HIT or MISS)
Note over Core: Batch statistics query
Core->>UC: statistics cache (all subjects)
alt Cache HIT
UC-->>Core: cached statistics
else Cache MISS
UC->>DB: getBatchStatisticsForSubjects()<br/>(2-3 queries instead of N×2)
DB-->>UC: statistics map
UC-->>Core: statistics (cached)
end
Core-->>API: MeetingDataCore
API-->>Client: JSON (without highlights)
Note over Cache,DB: Alternative: getMeetingDataCached path
Client->>Cache: getMeetingDataCached()
Cache->>Core: getMeetingDataCore()
Core-->>Cache: core data
Cache->>DB: getHighlightsForMeeting()<br/>(user-specific, NOT cached)
DB-->>Cache: highlights
Cache-->>Client: MeetingData (with highlights)
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
kouloumos
left a comment
There was a problem hiding this comment.
Solid perf improvement. The batch statistics approach is the right call -- N×2 queries down to 2-3 is a big win for meetings with many subjects. I've left a few comments inline and added tests for getBatchStatisticsForSubjects covering the main paths (new system, old system fallback, empty subjects): 15b3f68 -- feel free to cherry-pick.
2e0919c to
d8d91a6
Compare
|
Hey! Main has moved forward quite a bit and your branch was no longer in sync. To get things back into a clean and reviewable state, I cherry-picked your commits on top of the current main and force-pushed the result to this PR branch. To be safe, I've also kept a backup of your original branch (before the cherry-pick) here: I'll finish reviewing this shortly! |
d8d91a6 to
5dd8928
Compare
|
I force-pushed to address review comments (1, 2, 3, 4, 5):
|
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consolidates all meeting data logic in one file, eliminating the circular dependency between queries.ts and getMeetingData.ts. Reuses getPeopleForCityCached and getPartiesForCityCached from queries.ts instead of duplicating inline createCache calls.
5dd8928 to
715690e
Compare
|
Force-pushed with an additional refactor commit that consolidates meeting data logic:
All review comments have been addressed. This is ready to merge. |
🚀 Preview deployment ready!Preview URL: https://pr-192.preview.opencouncil.gr The preview will be automatically updated when you push new commits. This preview uses the staging database - any changes will affect other previews. |
🧹 Preview deployment cleaned upThe preview instance for this PR has been destroyed. Removed:
Automatic cleanup on PR close |
Summary
getBatchStatisticsForSubjects()unstable_cachewith proper tag-based invalidationcreateCachenow logs HIT/MISS per sub-query for visibilityManual testing plan
🤖 Generated with Claude Code
Note
Medium Risk
Touches core meeting data assembly and statistics calculation plus caching behavior; mistakes could cause stale/incorrect meeting page data or performance regressions despite being largely read-path changes.
Overview
Meeting data fetching is refactored to improve performance by splitting
getMeetingDatainto cacheablegetMeetingDataCoreand per-request composition of user-specifichighlightsingetMeetingDataCached.Core meeting sub-queries (city, people, parties, subjects, task status, and subject statistics) are wrapped in
unstable_cachewith tag-based invalidation, andcreateCachenow logsHIT/MISS/ERRtiming per key for visibility. Subject statistics are optimized via a newgetBatchStatisticsForSubjects()path that replaces per-subject DB querying with batched queries (with legacy fallback).Written by Cursor Bugbot for commit 2e0919c. This will update automatically on new commits. Configure here.
Greptile Summary
Refactored meeting data fetching to improve performance by splitting
getMeetingDatainto cacheablegetMeetingDataCoreand per-request composition with user-specifichighlights. Core sub-queries (city, people, parties, subjects, task status, statistics) are wrapped inunstable_cachewith tag-based invalidation. Statistics optimized viagetBatchStatisticsForSubjects()replacing N×2 per-subject queries with 2-3 batched queries, supporting both new utterance-based and legacy systems.Key changes:
getMeetingDataCorereturnsMeetingDataCore(without highlights) with individually cached sub-queriesgetMeetingDataCachedcomposes core data with fresh per-user highlightsgetBatchStatisticsForSubjectsbatches all utterances and speaker segments into 2-3 queriescreateCachenow logs HIT/MISS/ERR with timing per key/api/cities/[cityId]/meetings/[meetingId]now returnsMeetingDataCore(highlights were never used by consumers)Potential concerns:
Object.fromEntries(map)- Map doesn't JSON-serialize, so conversion is necessary but adds overheadcity:${cityId}:meetingstag which invalidates all meeting sub-queries togetherConfidence Score: 4/5
src/lib/getMeetingData.tsandsrc/lib/statistics.tsto verify cache hit rates and statistics accuracy across both new and old subject systemsImportant Files Changed
MeetingDataCoreand cacheable sub-queries with highlights fetched separately; statistics now batchedgetBatchStatisticsForSubjects()to replace N×2 queries with 2-3 batched queries with dual-system supportgetMeetingDataCoreinstead ofgetMeetingData(no highlights)Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Request getMeetingDataCached] --> B[React cache dedup check] B --> C[getMeetingDataCore + getHighlights in parallel] C --> D[Meeting + Transcript uncached] C --> E[Cached: city with geometry] C --> F[Cached: people] C --> G[Cached: parties] C --> H[Cached: subjects] C --> I[Cached: taskStatus] H --> K[Cached: subjectStatistics] K --> L[getBatchStatisticsForSubjects] L --> M[Query 1: All utterances batch] L --> N[Query 2: Old system fallback batch] L --> O[Query 3: Speaker segments batch] O --> P[Compute stats per subject] P --> Q[Map to Object for cache] Q --> R[Merge with subjects] D --> R E --> R F --> R G --> R I --> R R --> S[MeetingDataCore ready] C --> T[Fresh highlights per user] S --> U[Combine into MeetingData] T --> U style L fill:#90EE90 style M fill:#90EE90 style N fill:#90EE90 style O fill:#90EE90 style E fill:#87CEEB style F fill:#87CEEB style G fill:#87CEEB style H fill:#87CEEB style I fill:#87CEEB style K fill:#87CEEB style D fill:#FFB6C1 style T fill:#FFB6C1Last reviewed commit: 715690e