Keep the payout fields, not the whole entries, for the wallet total - #1571
Conversation
The wallet's pending-earnings figure reads payout_at and pending_payout_value and nothing else, but the bridge answers with whole entries. Measured across four active accounts, the two calls this component makes retain about 660 KB each time the wallet is opened, roughly 100 KB of post bodies and 500 KB of voter records, to produce one number. Projected on arrival it is 2.8 KB. The wire cost is unchanged and cannot be fixed here, since the bridge sends what it sends. What this buys is retained memory, which is what bounds how many renderer replicas fit on a host. The projection answers under its own key. accountPostsPage is shared with the waves composer and the decks user column, both of which consume whole entries, and handing either a projected row would be the fault behind #1556. A test pins that the key is the shared one plus a marker rather than the shared one.
Code Review by Qodo
1.
|
|
Warning Review limit reached
Next review available in: 41 minutes Limit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Summary by QodoProject wallet pending payouts to reduce retained memory
AI Description
Diagram
High-Level Assessment
Files changed (3)
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 80cae0cc3c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return queryOptions({ | ||
| queryKey: [...base.queryKey, "pending-payouts"], | ||
| queryFn: async (): Promise<PendingPayout[]> => { | ||
| const entries = (await fetchEntries()) ?? []; |
There was a problem hiding this comment.
Forward the query context to preserve request cancellation
When these wallet queries are cancelled because the user navigates away, changes profiles, or code calls cancelQueries, this wrapper discards React Query's context and invokes fetchEntries() without its abort signal. The wrapped SDK query explicitly forwards that signal to getAccountPosts (packages/sdk/src/modules/posts/queries/get-account-posts-query-options.ts, lines 83–97), so the newly wrapped requests now continue downloading and retaining the full post/vote payload after their consumer is gone, undermining the memory reduction this change targets. Accept the query context here and pass it through to the SDK query function.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Correct, and fixed in 8994fdf. The wrapper now takes React Query's context and passes it straight through, so signal reaches getAccountPosts again. Covered by a test that fails if the argument is dropped.
Greptile SummaryThe PR introduces a wallet-specific React Query projection that retains only payout timestamps and values while preserving request cancellation and isolating the projected rows under a distinct cache key.
Confidence Score: 5/5The PR appears safe to merge. The previously reported cancellation failure is fixed because the wrapper forwards React Query’s context to the SDK query function, preserving the abort signal, and no blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/web/src/api/queries/pending-payouts-query.ts | Adds a cache-isolated projection over the SDK account-post query and correctly forwards React Query’s cancellation context. |
| apps/web/src/app/(dynamicPages)/profile/[username]/wallet/_components/profile-wallet-pending-earnings.tsx | Switches pending-earnings post and comment queries to the lightweight payout projection. |
| apps/web/src/specs/api/pending-payouts-query.spec.ts | Covers projected shape, distinct cache identity, empty responses, cancellation forwarding, and account filtering. |
| apps/web/src/api/queries/index.ts | Exports the new pending-payout query helper from the web query barrel. |
Sequence Diagram
sequenceDiagram
participant Wallet as Pending earnings component
participant RQ as React Query
participant Projection as pendingPayoutsQueryOptions
participant SDK as SDK account-posts query
participant Bridge as Bridge API
Wallet->>RQ: Query posts/comments with projected cache key
RQ->>Projection: queryFn(context with abort signal)
Projection->>SDK: Forward complete query context
SDK->>Bridge: Fetch account entries with signal
Bridge-->>SDK: Full entries
SDK-->>Projection: Entry array
Projection->>Projection: Filter author and retain payout fields
Projection-->>RQ: PendingPayout array
RQ-->>Wallet: Lightweight cached rows
Reviews (2): Last reviewed commit: "Forward the query context and filter the..." | Re-trigger Greptile
| queryFn: async (): Promise<PendingPayout[]> => { | ||
| const entries = (await fetchEntries()) ?? []; |
There was a problem hiding this comment.
Query cancellation context is discarded
When the wallet unmounts during either request, React Query aborts its signal, but this wrapper calls fetchEntries without forwarding that context, so the bridge RPC and nested post-resolution work continue until completion or timeout.
| queryFn: async (): Promise<PendingPayout[]> => { | |
| const entries = (await fetchEntries()) ?? []; | |
| queryFn: async (ctx): Promise<PendingPayout[]> => { | |
| const entries = (await fetchEntries(ctx)) ?? []; |
There was a problem hiding this comment.
Fixed in 8994fdf, along the lines of the suggestion. Added a test asserting the exact context object reaches the SDK query function and that its signal is the one the caller supplied.
Code Review by Qodo
1.
|
The wrapper called the SDK query function with no arguments, so the abort signal React Query hands it never reached the bridge call: a wallet the reader had navigated away from kept downloading and resolving entries, which is what this projection exists to avoid. Also drops entries whose author is not the account whose wallet is open, so a node answering with anything else cannot move the total, and moves the builder to api/queries where app-specific queries live.
Closes #1570.
The wallet's pending-earnings figure reads
payout_atandpending_payout_valueand nothing else, but the bridge answers with whole entries.Measured across four active accounts, the two calls this component makes retain about 660 KB each time the wallet is opened, roughly 100 KB of post bodies and 500 KB of voter records, to produce one number. Projected on arrival it is 2.8 KB.
Be clear about what this does and does not buy: the wire cost is unchanged, because the bridge sends what it sends, and only an endpoint of our own or a field on the account could avoid that. What it buys is retained memory, which is what bounds how many renderer replicas fit on a host (#1559).
The projection answers under its own cache key.
accountPostsPageis shared with the waves composer and the decks user column, both of which consume whole entries, and handing either a projected row would be the fault behind #1556. A test pins that the key is the shared one plus a marker rather than the shared one itself, alongside the projection and an empty answer.It is a plain projection rather than
withSlimPageEntries: slimming would add per-entry work for a surface that renders no card, and would only remove the 100 KB of bodies while leaving the 500 KB of votes.pnpm typecheckclean,pnpm testgreen (3028 tests).