Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Profile Caching #1441

Merged
merged 2 commits into from
Jan 2, 2025
Merged

feat: Profile Caching #1441

merged 2 commits into from
Jan 2, 2025

Conversation

alexrisch
Copy link
Collaborator

@alexrisch alexrisch commented Dec 30, 2024

Added initial data to profile queries
Cleaned up hydration handler to improve time to responsive Added prefetch to V3 DMs
Updated useMessageIsUnread to handle empty/loading state Added additional performance logs

Summary by CodeRabbit

Release Notes

  • Performance Improvements

    • Enhanced message fetching and processing performance logging.
    • Improved query data initialization and caching mechanisms.
  • Query Enhancements

    • Updated type definitions for profile socials and conversation messages queries.
    • Added more robust initial data handling for queries.
  • Code Optimization

    • Simplified import statements.
    • Improved error handling in conversation list and message tracking.
  • Prefetching

    • Added prefetching of conversation messages before navigation.
    • Updated handling of persisted conversation lists for accounts.

Added initial data to profile queries
Cleaned up hydration handler to improve time to responsive
Added prefetch to V3 DMs
Updated useMessageIsUnread to handle empty/loading state
Added additional performance logs
@alexrisch alexrisch requested a review from a team as a code owner December 30, 2024 11:23
Copy link
Contributor

coderabbitai bot commented Dec 30, 2024

Walkthrough

The pull request introduces several modifications across multiple components and query-related files, focusing on enhancing data fetching, type safety, and performance logging. The changes primarily involve updating the hydration state handling, improving conversation message prefetching, refining query configurations, and adding performance measurement for message retrieval. The modifications aim to optimize the data fetching process and provide more robust error handling and type definitions.

Changes

File Change Summary
components/StateHandlers/HydrationStateHandler.tsx Modified conversation list fetching logic, moved prefetchInboxIdQuery outside Promise.allSettled
components/V3DMListItem.tsx Added prefetchConversationMessages import, updated onPress callback dependency array
components/V3GroupConversationListItem.tsx Removed unused useEffect import
features/conversation-list/hooks/useMessageIsUnread.ts Removed useCurrentAccount import, added conditional check for topic existence
queries/useConversationMessages.ts Added performance logging for message fetching and processing
queries/useInboxProfileSocialsQuery.ts Enhanced type safety, updated return types, improved initial data handling
queries/useProfileSocialsQuery.ts Added type safety, modified query key and return types, improved initial data handling

Possibly related PRs

Suggested labels

3.0.0

Suggested reviewers

  • thierryskoda

Poem

🐰 Hydration's dance, a rabbit's delight,
Queries refined with algorithmic might.
Messages flow, performance takes flight,
Code evolves with each clever byte.
Performance logging, our technical sprite! 🚀


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5783ea8 and 6c98361.

📒 Files selected for processing (1)
  • queries/useConversationMessages.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • queries/useConversationMessages.ts

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

]);
prefetchInboxIdQuery({ account });
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this out as it's a prefetch, we don't want to await it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've put it there and we might need some refactoring for this but I think having the InboxId available is a must before showing the content to the user. Since we use it so much.

But again, with the refactor of accounts maybe that will be somewhere else or etc...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be cached better now, so I think it will be a better experience, where previously it was not cached

Copy link
Contributor

github-actions bot commented Dec 30, 2024

Performance Comparison Report

  • Current: 121047e - 2024-12-30 11:35:24Z
  • Baseline: release/3.0.0 (187d108) - 2024-12-30 11:34:05Z

Significant Changes To Duration

There are no entries

Meaningless Changes To Duration

Show entries
Name Type Duration Count
Avatar Image 10 runs render 1.1 ms → 1.1 ms 1 → 1
Avatar Image 50 runs render 1.1 ms → 1.0 ms (-0.0 ms, -1.9%) 1 → 1
Empty Avatar 10 runs render 0.7 ms → 0.9 ms (+0.2 ms, +28.6%) 🔴 1 → 1
Empty Avatar 50 runs render 0.7 ms → 0.7 ms (+0.0 ms, +6.1%) 1 → 1
Text Component with color prop - 10 runs render 0.0 ms → 0.2 ms (+0.2 ms, +Infinity%) 🔴 1 → 1
Text Component with default props - 10 runs render 0.4 ms → 0.1 ms (-0.3 ms, -75.0%) 🟢 1 → 1
Text Component with translation key - 10 runs render 0.2 ms → 0.2 ms 1 → 1
Text Component with weight and size - 10 runs render 0.2 ms → 0.2 ms 1 → 1
Show details
Name Type Duration Count
Avatar Image 10 runs render Baseline
Mean: 1.1 ms
Stdev: 0.3 ms (28.7%)
Runs: 1 1 2 1 1 1 1 1 1 1
Warmup runs: 3

Current
Mean: 1.1 ms
Stdev: 0.3 ms (28.7%)
Runs: 1 1 2 1 1 1 1 1 1 1
Warmup runs: 2
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Avatar Image 50 runs render Baseline
Mean: 1.1 ms
Stdev: 0.4 ms (35.2%)
Runs: 1 1 1 1 1 2 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 0 2 1 2 1 2 1 1 1 1 1 1 1 1 1 1 1 1
Warmup runs: 1

Current
Mean: 1.0 ms
Stdev: 0.3 ms (27.2%)
Runs: 2 1 1 1 1 0 2 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:
Empty Avatar 10 runs render Baseline
Mean: 0.7 ms
Stdev: 0.5 ms (69.0%)
Runs: 1 0 1 0 1 0 1 1 1 1
Warmup runs: 3

Current
Mean: 0.9 ms
Stdev: 0.3 ms (35.1%)
Runs: 1 1 1 1 1 1 1 1 0 1
Warmup runs: 2
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Empty Avatar 50 runs render Baseline
Mean: 0.7 ms
Stdev: 0.5 ms (72.5%)
Runs: 1 1 1 1 0 1 0 0 1 1 1 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 0 1 0 1 1 1 1 0 1 1 0 1 0
Warmup runs: 1

Current
Mean: 0.7 ms
Stdev: 0.5 ms (66.1%)
Runs: 1 1 1 1 1 1 1 0 1 1 1 1 1 1 0 1 0 0 1 1 1 1 1 0 0 1 0 1 0 1 0 1 1 0 1 1 1 0 0 0 1 1 1 1 1 0 1 0 1 1
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with color prop - 10 runs render Baseline
Mean: 0.0 ms
Stdev: 0.0 ms (NaN%)
Runs: 0 0 0 0 0 0 0 0 0 0
Warmup runs: 0

Current
Mean: 0.2 ms
Stdev: 0.4 ms (210.8%)
Runs: 0 1 0 1 0 0 0 0 0 0
Warmup runs: 0
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with default props - 10 runs render Baseline
Mean: 0.4 ms
Stdev: 0.5 ms (129.1%)
Runs: 0 1 0 1 0 0 0 1 0 1
Warmup runs: 0

Current
Mean: 0.1 ms
Stdev: 0.3 ms (316.2%)
Runs: 0 0 0 0 0 0 0 1 0 0
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with translation key - 10 runs render Baseline
Mean: 0.2 ms
Stdev: 0.4 ms (210.8%)
Runs: 0 0 0 0 1 1 0 0 0 0
Warmup runs: 1

Current
Mean: 0.2 ms
Stdev: 0.4 ms (210.8%)
Runs: 0 0 0 0 0 0 0 1 1 0
Warmup runs: 1
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:
Text Component with weight and size - 10 runs render Baseline
Mean: 0.2 ms
Stdev: 0.4 ms (210.8%)
Runs: 0 0 0 1 0 1 0 0 0 0
Warmup runs: 0

Current
Mean: 0.2 ms
Stdev: 0.4 ms (210.8%)
Runs: 1 0 1 0 0 0 0 0 0 0
Warmup runs: 0
Baseline
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Current
Mean: 1
Stdev: 0 (0.0%)
Runs: 1 1 1 1 1 1 1 1 1 1
Render issues:

Render Count Changes

There are no entries

Render Issues

There are no entries

Added Scenarios

There are no entries

Removed Scenarios

There are no entries

Generated by 🚫 dangerJS against 6c98361

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
components/V3DMListItem.tsx (1)

166-170: Handle prefetch errors and potential offline scenarios.

You're calling prefetchConversationMessages before navigating. While this strategy is good for performance, it might be beneficial to handle possible rejections (e.g., network issues, query failures) to provide user feedback. Consider including a catch or error boundary to handle failures gracefully, ensuring the app doesn't navigate with incomplete or stale data.

  const onPress = useCallback(async () => {
    try {
-     prefetchConversationMessages(currentAccount, topic);
+     await prefetchConversationMessages(currentAccount, topic);
    } catch (error) {
+     logger.error("Failed to prefetch conversation messages", error);
      // Possibly show a toast or fallback UI
    }
    navigate("Conversation", { topic });
  }, [topic, currentAccount]);
queries/useConversationMessages.ts (1)

Line range hint 85-92: Prefetch function is straightforward, but consider error handling.

The prefetchConversationMessages function focuses on performance optimization. However, you may want to handle scenarios where the query fails and log warnings or errors for better observability.

export const prefetchConversationMessages = async (
  account: string,
  topic: ConversationTopic
) => {
+ try {
    return queryClient.prefetchQuery(
      getConversationMessagesQueryOptions(account, topic)
    );
+ } catch (err) {
+   logger.warn("[prefetchConversationMessages] failed to prefetch", err);
+ }
};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 187d108 and 5783ea8.

📒 Files selected for processing (7)
  • components/StateHandlers/HydrationStateHandler.tsx (1 hunks)
  • components/V3DMListItem.tsx (2 hunks)
  • components/V3GroupConversationListItem.tsx (1 hunks)
  • features/conversation-list/hooks/useMessageIsUnread.ts (2 hunks)
  • queries/useConversationMessages.ts (1 hunks)
  • queries/useInboxProfileSocialsQuery.ts (4 hunks)
  • queries/useProfileSocialsQuery.ts (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/V3GroupConversationListItem.tsx
🧰 Additional context used
📓 Learnings (1)
features/conversation-list/hooks/useMessageIsUnread.ts (1)
Learnt from: alexrisch
PR: ephemeraHQ/converse-app#1067
File: components/Chat/Message/MessageActions.tsx:297-297
Timestamp: 2024-11-12T10:18:48.668Z
Learning: Due to current performance issues, directly accessing `useFramesStore.getState()` inside `useMemo` is acceptable in certain cases, even though it's generally considered an anti-pattern.
🔇 Additional comments (14)
features/conversation-list/hooks/useMessageIsUnread.ts (2)

4-4: Consolidate imports or avoid unused ones if possible.

The addition of useChatStore appears to be necessary here. However, ensure no other unused imports linger, as they can lead to confusion over dependencies in the long run.


28-28: Helpful check to prevent runtime errors.

Adding this safeguard ensures that the code doesn't break when topicsData[topic] is undefined. This makes the hook more robust, especially in scenarios where the topic might not be fully loaded yet.

components/StateHandlers/HydrationStateHandler.tsx (2)

36-36: Code comment clarification is good.

Explicitly noting that this call will create the client and set the conversation list from persistence helps future maintainers understand the underlying process. Good practice.


39-39: Deferred prefetch is logically consistent.

Calling prefetchInboxIdQuery after resolving the persisted conversation lists ensures that the inbox ID is always fetched in the correct sequence. This reduces the likelihood of race conditions.

queries/useInboxProfileSocialsQuery.ts (4)

2-2: Enhanced type safety recognized.

Importing QueryKey and useQueries from @tanstack/react-query is a solid approach toward maintaining strong type definitions in your query configuration.


14-17: Clearer return type for query keys.

Declaring the return type as QueryKey clarifies the type signature and improves IntelliSense for consumers.


40-43: Explicit promise return type.

Defining the function to return Promise<IProfileSocials[] | null> clarifies behavior for consumers, ensuring they handle both array and null scenarios.


72-82: Initial data logic for rehydration is well-structured.

The check for !account || !inboxId and presence in mmkv ensures the correct initial data is supplied or undefined if unavailable. This pattern helps maintain consistent, reactive data throughout the app.

queries/useProfileSocialsQuery.ts (4)

2-2: Adoption of QueryKey for improved type definitions.

Importing and using QueryKey from @tanstack/react-query is commendable; it reduces ambiguity around query keys in your application.


15-18: Function signature strongly typed.

Providing a typed return for profileSocialsQueryKey intensifies clarity on how query keys are structured, benefiting debugging and future refactors.


68-75: Graceful handling of initial data.

This approach properly checks MMKV storage before returning any data. It’s beneficial for offline or initial load states, preventing extraneous network calls when data is already available.


111-111: Refined fetch query type.

Switching to fetchQuery<IProfileSocials | null> appropriately reflects the possibility of no data (null). This reduces type confusion for consumers of the fetchQuery result.

components/V3DMListItem.tsx (1)

30-30: Import statement looks good.

Importing prefetchConversationMessages is consistent with its usage below. There's no immediate concern here.

queries/useConversationMessages.ts (1)

32-48: Performance logging implementation is well-structured.

Measuring fetch and processing times provides valuable insight into performance bottlenecks. The overall logic is coherent. Ensure that large logs—including message counts—do not negatively impact log parsing or lead to excessive verbosity.

Removed syncing on prefetch of conversation messages
@@ -63,7 +69,18 @@ const inboxProfileSocialsQueryConfig = (
// And automatic retries if there was an error fetching
refetchOnMount: false,
staleTime: 1000 * 60 * 60 * 24,
// persister: reactQueryPersister,
initialData: (): IProfileSocials[] | null | undefined => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return type should be inferred no?

@@ -62,6 +65,15 @@ const profileSocialsQueryConfig = (account: string, peerAddress: string) => ({
// And automatic retries if there was an error fetching
refetchOnMount: false,
staleTime: 1000 * 60 * 60 * 24,
initialData: (): ProfileSocialsData => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return type should be inferred no?

@@ -96,7 +108,7 @@ export const fetchProfileSocialsQuery = (
account: string,
peerAddress: string
) => {
return queryClient.fetchQuery<ProfileSocialsData>(
return queryClient.fetchQuery<IProfileSocials | null>(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of this I love having something like in useConversationMessages


export type ConversationMessagesQueryData = Awaited<
  ReturnType<typeof conversationMessagesQueryFn>
>;

and reusing ConversationMessagesQueryData everywhere we use queryClient...

const fetchInboxProfileSocials = async (
account: string,
inboxId: InboxId
): Promise<IProfileSocials[] | null> => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return type should be inferred no?

@alexrisch alexrisch merged commit d38bcce into release/3.0.0 Jan 2, 2025
6 checks passed
@alexrisch alexrisch deleted the ar/profile-caching branch January 2, 2025 03:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants