perf: fetch commitment history in parallel in RecentActivityFeed (Closes #1396) - #1725
Open
Aycode01 wants to merge 1 commit into
Open
Conversation
Replace the sequential for-loop in loadEvents with Promise.allSettled(commitments.map(...)), preserving the existing per-commitment try/catch-and-log behavior for failures. This drops feed render time from N x latency to max(latency) for N active commitments. Closes Commitlabs-Org#1396
|
@Aycode01 is attempting to deploy a commit to the 1nonly's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@Aycode01 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #1396
RecentActivityFeed.tsx'sloadEventspreviously fetched per-commitment history sequentially in afor-loop:Each
/api/commitments/{id}/historyrequest had to complete before the next one started. For a user with N active commitments, the feed took roughly N × single-request latency to render (instead ofmax(latency)), and the loading skeleton stayed visible the entire time.This PR replaces the sequential loop with
Promise.allSettled(commitments.map(...)), which issues all per-commitment history requests concurrently, dropping feed render time from N × latency to max(latency) — the loading skeleton disappears as soon as the slowest single request resolves, not after the sum of all of them.Behavior preserved
try/catchwithconsole.errorlogging on failure (unchanged from the original), so one failing commitment never blocks or breaks the rest of the feed.Promise.allSettled(per the issue's acceptance criteria) guarantees the aggregate never rejects even if an individual request does, and weflatMaponly fulfilled results.Changes
src/components/dashboard/RecentActivityFeed.tsxloadEventsto usePromise.allSettled(commitments.map(async (commitment) => { ... }))with the original per-commitment try/catch-and-log preserved inside each mapper.FeedEvent[](or[]on failure); the outerallSettledresult is flattened into a single event list.FeedEventtype to an intersection (HistoryEvent & { commitmentId: string }) so discriminated-union narrowing onevent.kindstill works.role="list"on the<ul>to satisfyjsx-a11y/no-redundant-roles.src/components/dashboard/RecentActivityFeed.test.tsx(new)Seven tests covering the feed, including:
apiGetwith never-resolving promises, renders the feed, and verifies all N requests are fired before any promise resolves. A sequential implementation could never pass this test, since the 2nd call would only fire after the 1st resolves.console.error) while the other's succeeds; asserts the successful commitment's events still render.Restored support files (new against
upstream/master)These files exist in the intended feature but were deleted from the repository by the destructive
1ecce7d2commit and never restored upstream — they currently 404 onupstream/master:src/lib/apiClient.tssrc/lib/client/apiClient.tssrc/utils/errorHelpers.tssrc/components/Skeleton.tsxType-safety fixes applied to the restored files
The restored files predate the repo's stricter
tsconfig.jsonsettings, so they were brought up to current standards:client/apiClient.ts: optional properties assigned conditionally to satisfyexactOptionalPropertyTypes.errorHelpers.ts:normalizeApiErrorbuilds its passthrough object with conditional field assignment (exact optional properties) and uses safe registry lookups undernoUncheckedIndexedAccess.Motivation
For a user with N active commitments, the sequential loop renders the feed after the sum of all request latencies. With
Promise.allSettled, it renders after the maximum single latency — a linear-to-constant improvement that matters most exactly when a user has many commitments (the loading skeleton stays visible for N× latency today).Testing
Run locally and passing:
npx prettier --checkon all 6 filesnpx eslinton all 6 files (0 errors)npx vitest run src/components/dashboard/RecentActivityFeed.test.tsx— 7/7 tests pass, including the new concurrency + resilience testsnpx tsc --noEmit— no errors in any of the changed filesChecklist
Promise.allSettled(commitments.map(...))