Temporary transactions page performance fix #2372

Merged
zachgoll merged 3 commits from zachgoll/transactions-page-temporary-perf-fix into main 2025-06-15 23:36:21 +08:00
zachgoll commented 2025-06-15 22:57:16 +08:00 (Migrated from github.com)

This PR is a temporary solution to speed up the transactions page. A longer-term fix will fully replace this very hacky solution, but will require a larger rework of the search query.

Before:

Type IPS Deviation Time/Iteration Iterations Total Time
COLD 0.275 ± 0.00% 3.64 s/i 1.000 3.638567s
WARM 0.431 ± 0.00% 2.32 s/i 5.000 11.598782s

After:

Type IPS Deviation Time/Iteration Iterations Total Time
COLD 0.344 ± 0.00% 2.91 s/i 1.000 2.908487s
WARM 2.767 ± 0.00% 361.45 ms/i 28.000 10.126426s
This PR is a temporary solution to speed up the transactions page. A longer-term fix will fully replace this very hacky solution, but will require a larger rework of the search query. Before: | Type | IPS | Deviation | Time/Iteration | Iterations | Total Time | |------|-----|-----------|----------------|------------|------------| | COLD | 0.275 | ± 0.00% | 3.64 s/i | 1.000 | 3.638567s | | WARM | 0.431 | ± 0.00% | 2.32 s/i | 5.000 | 11.598782s | After: | Type | IPS | Deviation | Time/Iteration | Iterations | Total Time | |------|-----|-----------|----------------|------------|------------| | COLD | 0.344 | ± 0.00% | 2.91 s/i | 1.000 | 2.908487s | | WARM | 2.767 | ± 0.00% | 361.45 ms/i | 28.000 | 10.126426s |
cursor[bot] (Migrated from github.com) reviewed 2025-06-15 23:00:55 +08:00
cursor[bot] (Migrated from github.com) left a comment

Bug: Transaction Cache Invalidation and Key Issues

The transaction index page's caching mechanism has several flaws:

  1. Stale Data on Deletion: Cache invalidation fails when entries are hard-deleted, as the cache key uses maximum(:updated_at) of existing entries. This can result in stale cached IDs, leading to fewer transactions displayed.
  2. Cache Key Inconsistency: The cache key is built from raw request.query_parameters.to_h, which may not match the processed search_params used for the actual query (e.g., due to default date ranges), causing cache misses or incorrect results.
  3. Cache Fragmentation: Including UI-only parameters like focused_record_id in the cache key (which Pagy explicitly excludes from its parameters) causes unnecessary cache fragmentation, reducing hit rates and increasing memory usage.

app/controllers/transactions_controller.rb#L25-L40

f876176626/app/controllers/transactions_controller.rb (L25-L40)

Fix in Cursor


Was this report helpful? Give feedback by reacting with 👍 or 👎

<details open> <summary><h3>Bug: Transaction Cache Invalidation and Key Issues</h3></summary> The transaction index page's caching mechanism has several flaws: 1. **Stale Data on Deletion:** Cache invalidation fails when entries are hard-deleted, as the cache key uses `maximum(:updated_at)` of *existing* entries. This can result in stale cached IDs, leading to fewer transactions displayed. 2. **Cache Key Inconsistency:** The cache key is built from raw `request.query_parameters.to_h`, which may not match the processed `search_params` used for the actual query (e.g., due to default date ranges), causing cache misses or incorrect results. 3. **Cache Fragmentation:** Including UI-only parameters like `focused_record_id` in the cache key (which Pagy explicitly excludes from its parameters) causes unnecessary cache fragmentation, reducing hit rates and increasing memory usage. <p></p> <details> <summary><code>app/controllers/transactions_controller.rb#L25-L40</code></summary> https://github.com/maybe-finance/maybe/blob/f876176626befdbbf98666c7cb235a88bdfb3279/app/controllers/transactions_controller.rb#L25-L40 </details> <a href="https://cursor.com/open?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MSJ9.eyJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7ImJ1ZyI6ImV5SnNiMk5oZEdsdmJuTWlPbHQ3SW1acGJHVWlPaUpoY0hBdlkyOXVkSEp2Ykd4bGNuTXZkSEpoYm5OaFkzUnBiMjV6WDJOdmJuUnliMnhzWlhJdWNtSWlMQ0p6ZEdGeWRFeHBibVVpT2pJMUxDSmxibVJNYVc1bElqbzBNQ3dpWTI5a1pVeHBibVZ6SWpwYlhYMWRMQ0pwWkNJNklqTTFZalEwTUdFMUxUTTJPVE10TkRFd1lpMDRNRGszTFdSbVl6a3lNV0poTVRKaU55SXNJbVJsYzJOeWFYQjBhVzl1SWpvaVZHaGxJSFJ5WVc1ellXTjBhVzl1SUdsdVpHVjRJSEJoWjJVbmN5QmpZV05vYVc1bklHMWxZMmhoYm1semJTQm9ZWE1nYzJWMlpYSmhiQ0JtYkdGM2N6cGNiakV1SUNBcUtsTjBZV3hsSUVSaGRHRWdiMjRnUkdWc1pYUnBiMjQ2S2lvZ1EyRmphR1VnYVc1MllXeHBaR0YwYVc5dUlHWmhhV3h6SUhkb1pXNGdaVzUwY21sbGN5QmhjbVVnYUdGeVpDMWtaV3hsZEdWa0xDQmhjeUIwYUdVZ1kyRmphR1VnYTJWNUlIVnpaWE1nWUcxaGVHbHRkVzBvT25Wd1pHRjBaV1JmWVhRcFlDQnZaaUFxWlhocGMzUnBibWNxSUdWdWRISnBaWE11SUZSb2FYTWdZMkZ1SUhKbGMzVnNkQ0JwYmlCemRHRnNaU0JqWVdOb1pXUWdTVVJ6TENCc1pXRmthVzVuSUhSdklHWmxkMlZ5SUhSeVlXNXpZV04wYVc5dWN5QmthWE53YkdGNVpXUXVYRzR5TGlBZ0tpcERZV05vWlNCTFpYa2dTVzVqYjI1emFYTjBaVzVqZVRvcUtpQlVhR1VnWTJGamFHVWdhMlY1SUdseklHSjFhV3gwSUdaeWIyMGdjbUYzSUdCeVpYRjFaWE4wTG5GMVpYSjVYM0JoY21GdFpYUmxjbk11ZEc5ZmFHQXNJSGRvYVdOb0lHMWhlU0J1YjNRZ2JXRjBZMmdnZEdobElIQnliMk5sYzNObFpDQmdjMlZoY21Ob1gzQmhjbUZ0YzJBZ2RYTmxaQ0JtYjNJZ2RHaGxJR0ZqZEhWaGJDQnhkV1Z5ZVNBb1pTNW5MaXdnWkhWbElIUnZJR1JsWm1GMWJIUWdaR0YwWlNCeVlXNW5aWE1wTENCallYVnphVzVuSUdOaFkyaGxJRzFwYzNObGN5QnZjaUJwYm1OdmNuSmxZM1FnY21WemRXeDBjeTVjYmpNdUlDQXFLa05oWTJobElFWnlZV2R0Wlc1MFlYUnBiMjQ2S2lvZ1NXNWpiSFZrYVc1bklGVkpMVzl1YkhrZ2NHRnlZVzFsZEdWeWN5QnNhV3RsSUdCbWIyTjFjMlZrWDNKbFkyOXlaRjlwWkdBZ2FXNGdkR2hsSUdOaFkyaGxJR3RsZVNBb2QyaHBZMmdnVUdGbmVTQmxlSEJzYVdOcGRHeDVJR1Y0WTJ4MVpHVnpJR1p5YjIwZ2FYUnpJSEJoY21GdFpYUmxjbk1wSUdOaGRYTmxjeUIxYm01bFkyVnpjMkZ5ZVNCallXTm9aU0JtY21GbmJXVnVkR0YwYVc5dUxDQnlaV1IxWTJsdVp5Qm9hWFFnY21GMFpYTWdZVzVrSUdsdVkzSmxZWE5wYm1jZ2JXVnRiM0o1SUhWellXZGxMaUlzSW1OdmJtWnBaR1Z1WTJVaU9qQXVOak14TlRrd01qYzJORE14T1RVMUxDSmpZWFJsWjI5eWVTSTZJbEJQVkVWT1ZFbEJURjlGUkVkRlgwTkJVMFVpZlEiLCJicmFuY2giOiJ6YWNoZ29sbC90cmFuc2FjdGlvbnMtcGFnZS10ZW1wb3JhcnktcGVyZi1maXgifSwiaWF0IjoxNzQ5OTk5NjU1LCJleHAiOjE3NTA2MDQ0NTV9.O7EXYf6jg_Clh_O432YD1YNtVYCBQT19xAmkQ6jnMY7M3jlWHkdxyjzcoRiZrDqMo5XjF2Qqvn7C2T8ObGw8c9ddsNK7bjFim8NdbqwZyZfek9NolxGd6VB4OI6u5My6VwK-jffwzJaWDsRCHZq0gbIdl2rWkuODp7hNF_j-4Pb-Stbex1fceKsG8N6MdBUG1CHM5gYIOMOl5GpAYZ5Txa6q-Gqw1LcJA951nIO8mIB5NUn6jlbTJ6XRRqo19ZZ9OAW6tCmmbfoOTQLAyrF40Nrb4jZthpgik_WPrLgIbLyCzUYGXHtf0_6uON4Xn2hOmMlRMMJmpkhLtXKFmB5_aQ">Fix in Cursor</a> </details> --- _Was this report helpful? Give feedback by reacting with 👍 or 👎_
cursor[bot] (Migrated from github.com) reviewed 2025-06-15 23:10:50 +08:00
cursor[bot] (Migrated from github.com) left a comment

Bug: Caching Failures and Type Errors in Pagination

The new caching and pagination logic in TransactionsController#index introduces several issues:

  • Cache Inconsistency & Performance: The fallback logic for handling out-of-bounds page requests runs outside the cache block. This causes the cache to store empty results for invalid page numbers, while the fallback correctly fetches data for the last valid page. This leads to a UI/cache mismatch on subsequent requests for the same invalid page, and the fallback itself performs uncached database queries, negating performance benefits.
  • Type Mismatches: items_per_page (a string from request parameters) is passed directly to ActiveRecord::QueryMethods#limit, which expects an integer, potentially causing a runtime error. Similarly, current_page and items_per_page are passed as strings to the Pagy.new constructor, which expects integers, potentially leading to type errors or incorrect pagination behavior.

app/controllers/transactions_controller.rb#L64-L85

a087168b66/app/controllers/transactions_controller.rb (L64-L85)

Fix in Cursor


Was this report helpful? Give feedback by reacting with 👍 or 👎

<details open> <summary><h3>Bug: Caching Failures and Type Errors in Pagination</h3></summary> The new caching and pagination logic in `TransactionsController#index` introduces several issues: * **Cache Inconsistency & Performance:** The fallback logic for handling out-of-bounds page requests runs *outside* the cache block. This causes the cache to store empty results for invalid page numbers, while the fallback correctly fetches data for the last valid page. This leads to a UI/cache mismatch on subsequent requests for the same invalid page, and the fallback itself performs uncached database queries, negating performance benefits. * **Type Mismatches:** `items_per_page` (a string from request parameters) is passed directly to `ActiveRecord::QueryMethods#limit`, which expects an integer, potentially causing a runtime error. Similarly, `current_page` and `items_per_page` are passed as strings to the `Pagy.new` constructor, which expects integers, potentially leading to type errors or incorrect pagination behavior. <p></p> <details> <summary><code>app/controllers/transactions_controller.rb#L64-L85</code></summary> https://github.com/maybe-finance/maybe/blob/a087168b66c35afc630448a72e0cd5e46b67fe83/app/controllers/transactions_controller.rb#L64-L85 </details> <a href="https://cursor.com/open?data=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJ1Z2JvdC12MSJ9.eyJ0eXBlIjoiQlVHQk9UX0ZJWF9JTl9DVVJTT1IiLCJkYXRhIjp7ImJ1ZyI6ImV5SnNiMk5oZEdsdmJuTWlPbHQ3SW1acGJHVWlPaUpoY0hBdlkyOXVkSEp2Ykd4bGNuTXZkSEpoYm5OaFkzUnBiMjV6WDJOdmJuUnliMnhzWlhJdWNtSWlMQ0p6ZEdGeWRFeHBibVVpT2pZMExDSmxibVJNYVc1bElqbzROU3dpWTI5a1pVeHBibVZ6SWpwYlhYMWRMQ0pwWkNJNkltVXpNR1ptTWprekxXVTNNVFV0TkdGaE55MWlNVGRpTFRabVl6UXpOMk0wTkRaaU15SXNJbVJsYzJOeWFYQjBhVzl1SWpvaVZHaGxJRzVsZHlCallXTm9hVzVuSUdGdVpDQndZV2RwYm1GMGFXOXVJR3h2WjJsaklHbHVJR0JVY21GdWMyRmpkR2x2Ym5ORGIyNTBjbTlzYkdWeUkybHVaR1Y0WUNCcGJuUnliMlIxWTJWeklITmxkbVZ5WVd3Z2FYTnpkV1Z6T2x4dVhHNHFJQ0FnS2lwRFlXTm9aU0JKYm1OdmJuTnBjM1JsYm1ONUlDWWdVR1Z5Wm05eWJXRnVZMlU2S2lvZ1ZHaGxJR1poYkd4aVlXTnJJR3h2WjJsaklHWnZjaUJvWVc1a2JHbHVaeUJ2ZFhRdGIyWXRZbTkxYm1SeklIQmhaMlVnY21WeGRXVnpkSE1nY25WdWN5QXFiM1YwYzJsa1pTb2dkR2hsSUdOaFkyaGxJR0pzYjJOckxpQlVhR2x6SUdOaGRYTmxjeUIwYUdVZ1kyRmphR1VnZEc4Z2MzUnZjbVVnWlcxd2RIa2djbVZ6ZFd4MGN5Qm1iM0lnYVc1MllXeHBaQ0J3WVdkbElHNTFiV0psY25Nc0lIZG9hV3hsSUhSb1pTQm1ZV3hzWW1GamF5QmpiM0p5WldOMGJIa2dabVYwWTJobGN5QmtZWFJoSUdadmNpQjBhR1VnYkdGemRDQjJZV3hwWkNCd1lXZGxMaUJVYUdseklHeGxZV1J6SUhSdklHRWdWVWt2WTJGamFHVWdiV2x6YldGMFkyZ2diMjRnYzNWaWMyVnhkV1Z1ZENCeVpYRjFaWE4wY3lCbWIzSWdkR2hsSUhOaGJXVWdhVzUyWVd4cFpDQndZV2RsTENCaGJtUWdkR2hsSUdaaGJHeGlZV05ySUdsMGMyVnNaaUJ3WlhKbWIzSnRjeUIxYm1OaFkyaGxaQ0JrWVhSaFltRnpaU0J4ZFdWeWFXVnpMQ0J1WldkaGRHbHVaeUJ3WlhKbWIzSnRZVzVqWlNCaVpXNWxabWwwY3k1Y2Jpb2dJQ0FxS2xSNWNHVWdUV2x6YldGMFkyaGxjem9xS2lCZ2FYUmxiWE5mY0dWeVgzQmhaMlZnSUNoaElITjBjbWx1WnlCbWNtOXRJSEpsY1hWbGMzUWdjR0Z5WVcxbGRHVnljeWtnYVhNZ2NHRnpjMlZrSUdScGNtVmpkR3g1SUhSdklHQkJZM1JwZG1WU1pXTnZjbVE2T2xGMVpYSjVUV1YwYUc5a2N5TnNhVzFwZEdBc0lIZG9hV05vSUdWNGNHVmpkSE1nWVc0Z2FXNTBaV2RsY2l3Z2NHOTBaVzUwYVdGc2JIa2dZMkYxYzJsdVp5QmhJSEoxYm5ScGJXVWdaWEp5YjNJdUlGTnBiV2xzWVhKc2VTd2dZR04xY25KbGJuUmZjR0ZuWldBZ1lXNWtJR0JwZEdWdGMxOXdaWEpmY0dGblpXQWdZWEpsSUhCaGMzTmxaQ0JoY3lCemRISnBibWR6SUhSdklIUm9aU0JnVUdGbmVTNXVaWGRnSUdOdmJuTjBjblZqZEc5eUxDQjNhR2xqYUNCbGVIQmxZM1J6SUdsdWRHVm5aWEp6TENCd2IzUmxiblJwWVd4c2VTQnNaV0ZrYVc1bklIUnZJSFI1Y0dVZ1pYSnliM0p6SUc5eUlHbHVZMjl5Y21WamRDQndZV2RwYm1GMGFXOXVJR0psYUdGMmFXOXlMaUlzSW1OdmJtWnBaR1Z1WTJVaU9qQXVOak15TlRZMk1qZ3pPRGM1TmpBNU5pd2lZMkYwWldkdmNua2lPaUpNVDBkSlExOUNWVWNpZlEiLCJicmFuY2giOiJ6YWNoZ29sbC90cmFuc2FjdGlvbnMtcGFnZS10ZW1wb3JhcnktcGVyZi1maXgifSwiaWF0IjoxNzUwMDAwMjUwLCJleHAiOjE3NTA2MDUwNTB9.meSF1cOZlQu6ci3CxcphiOpYV_WXs1kMQBV2mZBrEufOLrZaLJ-Za3Vgh8wr53bB73h3r97mX-nwDZGyZS89ipaNgUZcjYtWsvSIs1g_UWXNwEw0vfyUzWE87OTomni4Qv-XJ4XhGazjjpQW7_m3eEhFtP7qozGpnrYzThggP20WDfWKYwbps7f8hxJlfQ0J-FVfZvGA2xxVZwwsCqkEdkH3CTHpmSqZLWzZlgeh8eA-1r5IketZkAtqTs5av0kfANXNtfQ9wceCsMyCdHuCC8HJtkkB8P-O5nvGN7O-h2XJ8s4nQXn47-Wa6t0DSX9Em5qKru9z9h9Nl2AY79wVtw">Fix in Cursor</a> </details> --- _Was this report helpful? Give feedback by reacting with 👍 or 👎_
cursor[bot] (Migrated from github.com) reviewed 2025-06-15 23:35:03 +08:00
cursor[bot] (Migrated from github.com) left a comment

BugBot reviewed your changes and found no bugs!


Was this report helpful? Give feedback by reacting with 👍 or 👎

### ✅ BugBot reviewed your changes and found no bugs! --- _Was this report helpful? Give feedback by reacting with 👍 or 👎_
Sign in to join this conversation.