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

refactor: [M3-5181] - React Query for Events #9949

Merged
merged 54 commits into from
Jan 26, 2024

Conversation

bnussman-akamai
Copy link
Member

@bnussman-akamai bnussman-akamai commented Dec 1, 2023

Description 📝

  • React Query-ifys our events / events polling system
  • This PR's polling system should match the behavior of the existing polling system. The main changes revolve around the fact that we are now storing and retrieving data from the React Query cache.
  • This is take two of refactor: [M3-5181] - RQ-ify Events #9416 because we had to revert it fix: Revert React Query for events (#9416) #9444
    • The big "bug" with that PR was that useEventsInfiniteQuery was mounted many times, which also mounted the cache updating code many times, which caused many renders to happen when event were polled. This PR fixed that by only mounting a polling hook that update the cache once.
    • This PR takes some inspiration from refactor: [M3-5181] - RQ-ify Events #9416, but is different in some ways

Main Additions

useEventsPoller ⏲️

  • A hook mounted at the root of the app, which is responsible for polling the events endpoint for new events
  • This hook is responsible for
    • Updating the cache based on the events it polls
    • Showing toast notifications for global toasts (like volume_delete for example)
    • Invoking our React Query event handlers (volumeEventsHandler for example)

useInProgressEvents 📇

  • A hook that returns only active / in-progress events
  • Used in LinodeRow for example

useEventsInfiniteQuery 📃

  • Used to render lists of events
  • This is used for EventsLanding, LinodeActivity, and the Event Menu

Other mentions

  • Removes rxjs dependency 🎉
  • Removes events completely from Redux 🗑️

How to test 🧪

  • Verify that all "real-time" feature of Cloud Manager work
    • For example, rebooting a Linode, shutting down a Linode, resizing a Linode, ...
  • Test polling behavior compared to production
    • Verify that this PR does not cause a significant change in the frequency in which we poll the events endpoint
  • Test the http://localhost:3000/events page
    • Verify the infinite scrolling works as expected
    • Verify the events are in the correct order
    • Verify new events show up in realtime
  • Test the Linode Details events tab
    • Verify the infinite scrolling works as expected
    • Verify the events are in the correct order
    • Verify new events show up in realtime
  • Test on a large account
  • Check for bad performance
  • Check the functionality of the Events / Notification Menu in the top navigation
  • Check logic and patterns in packages/manager/src/queries/events.ts and look for any issues, mistakes, or 🚩

As an Author I have considered 🤔

  • 👀 Doing a self review
  • ❔ Our contribution guidelines
  • 🤏 Splitting feature into small PRs
  • ➕ Adding a changeset
  • 🧪 Providing/Improving test coverage
  • 🔐 Removing all sensitive information from the code and PR description
  • 🚩 Using a feature flag to protect the release
  • 👣 Providing comprehensive reproduction steps
  • 📑 Providing or updating our documentation
  • 🕛 Scheduling a pair reviewing session
  • 📱 Providing mobile support
  • ♿ Providing accessibility support

@bnussman-akamai bnussman-akamai added Work in Progress React Query Relating to the transition to use React Query labels Dec 1, 2023
@bnussman-akamai bnussman-akamai self-assigned this Dec 1, 2023
@bnussman-akamai bnussman-akamai requested a review from a team as a code owner December 1, 2023 05:14
@bnussman-akamai bnussman-akamai requested review from hana-akamai and abailly-akamai and removed request for a team December 1, 2023 05:14
@bnussman-akamai bnussman-akamai changed the title refactor: React Query for Events refactor: [M3-5181] - React Query for Events Dec 1, 2023
Copy link

github-actions bot commented Dec 14, 2023

Coverage Report:
Base Coverage: 80.33%
Current Coverage: 81.15%

packages/manager/src/store/index.ts Outdated Show resolved Hide resolved
: intervalMultiplier * INTERVAL,
resetEventsPolling: () => queryClient.setQueryData<number>(queryKey, 1),
};
};
Copy link
Contributor

@hkhalil-akamai hkhalil-akamai Jan 11, 2024

Choose a reason for hiding this comment

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

The tl;dr of this hook is that it globally keeps track of a single number (the polling interval) and exposes operations like resetting and incrementing.

It's a little bit convoluted (hacky even) using the RQ store to store this value globally (another alternative would be to use Context, or the package you mentioned). The reason I chose to do it this way was to keep the polling hook and the polling interval hook tightly coupled (e.g., resetting one would reset the other).

In the original incarnation of RQ Events this hook was necessary since multiple polling hooks were mounted and they all needed to be synchronized. Now that we only have one instance of the polling hook, it may no longer be necessary. It may be possible to have the single polling hook maintain its interval using useState.

Copy link
Contributor

@hkhalil-akamai hkhalil-akamai left a comment

Choose a reason for hiding this comment

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

Left some minor comments and suggestions, but overall this PR is looking really good. Tested with all the steps listed in the two predecessor PRs (Part 1 & Part 2) and looks good.

We should also test in a large account to make sure the performance issues from the previous incarnation are resolved.

@@ -69,7 +69,6 @@
"redux": "^4.0.4",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0",
"rxjs": "^5.5.6",
Copy link
Contributor

Choose a reason for hiding this comment

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

Glad we can still remove this 🎉

Copy link
Member Author

Choose a reason for hiding this comment

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

Me too 😮‍💨

Copy link
Contributor

Choose a reason for hiding this comment

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

Changes here aren't directly related to the ticket; should we move them to another PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I probably should have done that. I chose to move some state around to reduce the number of renders caused by state changes in App.tsx. I think the change is pretty safe so I'm okay with leaving it if everyone else is

Copy link
Contributor

Choose a reason for hiding this comment

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

Noice 🤩

export const linodeEventsHandler = ({
event,
queryClient,
}: EventHandlerData) => {
const linodeId = event.entity?.id;

// Early return to cut down the number of invalidations.
Copy link
Contributor

Choose a reason for hiding this comment

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

The early return on lines 26-28 cuts down on a lot of repeated invalidations but has the negative consequence that Linodes may not reflect their current status accurately. For example, if a Linode is rebooted from another tab, it will still show as "Running".

It's not a major issue but might be worth discussing/capturing in separate ticket.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, good point. Probably out of scope because it's Linode specific, but we definitely could improve the Linode event handlers in general. I'm making myself a note to revisit this later down the road.

@@ -14,18 +14,14 @@ import { getLinkForEvent } from 'src/utilities/getEventsActionLink';

import { StyledGravatar } from './EventRow.styles';

interface ExtendedEvent extends Event {
_deleted?: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

Was this property unused?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it was unused. I'm not 100% sure but I think it was used way way in the past to determine if the event's entity was deleted for purposes of removing links that would lead to 404s in event messages. It would be good UX to bring this back somehow, but I can't think of a very efficient way to do it.

data-testid="linode-events-table"
emptyMessage="No recent activity for this Linode."
entityId={id}
errorMessage="There was an error retrieving activity for this Linode."
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want to drop this error message?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think I removed it because I chose to surface the API error directly for more transparency. Do you think we should stick with this more friendly error? I'm sure it's a rare occurrence

@@ -366,6 +366,7 @@ const formatNotificationForDisplay = (
): NotificationItem => ({
body: <RenderNotification notification={notification} onClose={onClose} />,
countInTotal: shouldIncludeInCount,
eventId: -1,
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure if I fully understand why this was not needed before

Copy link
Contributor

Choose a reason for hiding this comment

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

Not directly related to this PR, but I noticed we're missing event handlers for Kubernetes and now, VPC

Copy link
Member Author

Choose a reason for hiding this comment

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

Good call. I can make a ticket for LKE.

@dwiley-akamai Should we make one for VPC?

Copy link
Contributor

@dwiley-akamai dwiley-akamai Jan 17, 2024

Choose a reason for hiding this comment

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

I'll create a ticket to investigate whether a handler is needed. My initial thought is due to the nature of the VPC events it probably isn't, but it warrants a closer look.

edit: created M3-7649

@bnussman-akamai bnussman-akamai added the Needs extra approvals Use for PRs that have high-impact changes where > 2 approvals are needed label Jan 16, 2024
Copy link
Contributor

@hkhalil-akamai hkhalil-akamai left a comment

Choose a reason for hiding this comment

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

Re-approving since first approval didn't count

Copy link
Contributor

@jaalah-akamai jaalah-akamai left a comment

Choose a reason for hiding this comment

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

Great work @bnussman 🎉

Copy link
Contributor

@jdamore-linode jdamore-linode left a comment

Choose a reason for hiding this comment

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

This is a huge achievement, thanks @bnussman-akamai! Especially appreciate the thorough docs and comments, as well as the new test coverage

packages/manager/src/queries/events/event.helpers.test.ts Outdated Show resolved Hide resolved
packages/manager/src/queries/events/event.helpers.test.ts Outdated Show resolved Hide resolved
packages/manager/src/queries/events/event.helpers.test.ts Outdated Show resolved Hide resolved
Co-authored-by: jdamore-linode <97627410+jdamore-linode@users.noreply.github.com>
@bnussman-akamai bnussman-akamai merged commit e4911df into linode:develop Jan 26, 2024
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs extra approvals Use for PRs that have high-impact changes where > 2 approvals are needed React Query Relating to the transition to use React Query Ready for Review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants