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

Fix WorkspaceContext over-fetching code locations on cascading updates. #26970

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

salazarm
Copy link
Contributor

@salazarm salazarm commented Jan 9, 2025

Summary & Motivation

The main issue is that previousLocationVersionsRef.current was only being updated after ALL code locations were fetched. That means that whenever a code location was fetched, we'd think that all of the code locations were stale again, including the one we just fetched, because previousLocationVersionsRef.current was still pointing to the old version. To fix this I instead update previousLocationVersionsRef.current after each individual fetch. In addition, I added some extra guards within fetchLocationData itself to prevent overfetching due to someone calling refetch multiple times.

How I Tested These Changes

Added a jest test that failed without these changes.

Copy link

github-actions bot commented Jan 9, 2025

Deploy preview for dagit-core-storybook ready!

✅ Preview
https://dagit-core-storybook-4vwode2c4-elementl.vercel.app
https://marco-fe-749-investigate-duplicated-code-location-queries.core-storybook.dagster-docs.io

Built with commit 01b5958.
This pull request is being automatically deployed with vercel-action

Comment on lines +363 to +364
if (fetchingStatusesRef.current[localKey]) {
return fetchingStatusesRef.current[localKey];
Copy link
Member

Choose a reason for hiding this comment

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

should there be an await here? Im confused by the different types being returned here and below

Copy link
Contributor Author

@salazarm salazarm Jan 9, 2025

Choose a reason for hiding this comment

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

It behaves the same with or without an await

Copy link
Member

Choose a reason for hiding this comment

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

ah ok and the await below is just to sequence the deletion

return data;
} catch (error) {
console.error(`Error fetching location data for ${name}:`, error);
const localKey = name + '@' + (locationStatuses[name]?.versionKey ?? '');
Copy link
Member

Choose a reason for hiding this comment

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

[1]

fetchingStatusesRef,
});
previousLocationVersionsRef.current[location.name] =
locationStatuses[location.name]?.versionKey ?? '';
Copy link
Member

Choose a reason for hiding this comment

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

[1] I assume its fine since i see some bits of existing code that do it - but what is the expected result of using empty string when we get null ?

Copy link
Contributor Author

@salazarm salazarm Jan 9, 2025

Choose a reason for hiding this comment

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

In most cases this will not be null (since at this point, if we're fetching it should have been triggered by the code location status query), however it's possible to call the refetch function (exposed by WorkspaceContext) before the status query has come back in which case we would end up fetching the location once without the version and then again once we know what version we're fetching. There's no good way to guard against it since its possible the verison changed in between the refetch call and the status query being made/returning.

Copy link
Member

Choose a reason for hiding this comment

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

Is that a scenario under test or worth putting under test?

I don't have a strong mental model of all the mechanisms here so I'm just reacting to generally suspicious looking things

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I moved the version update into the fetchLocationData function instead. And instead of using the versionKey from the status update that triggered the fetch, I'm using the versionKey from the location response now so it should mitigate the weirdness here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But yeah, there was a theoretical issue here if the location query triggered by the refetch call was slower than a subsequent query... though actually... that issue can still happen... so maybe I should also check if the updateTimestamp is greater than the last version? ugh

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Random idea: But instead of polling for version keys on the code location status query, maybe I only use that query to get all of the locations, but separately poll the individual locations with a new query that takes the versionKey I'm currently on as an input and either returns the updated code location or a response indicating that I'm already up to date. Would that be easy to do? Could help eliminate some of the complexity here.

Copy link
Member

@alangenfeld alangenfeld left a comment

Choose a reason for hiding this comment

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

i think this stuff is mechanically complex enough that sprinkling in some comments would help readability ie // when <conditions this can happen> return the in flight fetch promise

Comment on lines +363 to +364
if (fetchingStatusesRef.current[localKey]) {
return fetchingStatusesRef.current[localKey];
Copy link
Member

Choose a reason for hiding this comment

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

ah ok and the await below is just to sequence the deletion

fetchingStatusesRef,
});
previousLocationVersionsRef.current[location.name] =
locationStatuses[location.name]?.versionKey ?? '';
Copy link
Member

Choose a reason for hiding this comment

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

Is that a scenario under test or worth putting under test?

I don't have a strong mental model of all the mechanisms here so I'm just reacting to generally suspicious looking things

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