facebook / facebook/relay

Concurrent execution of multiple `useLazyLoadQuery()` may lead to runtime errors due to missing data

Open
#5,131 2 comments 7 reactions 0 assignees View on GitHub
shared with relay team
Dominant language
Rust
Stars
19k
Forks
1.9k
PR merge metrics
No merged PRs in 30d

Description

Hello! 👋

This is either I am doing something wrong, or there is an issue that I believe is serious enough to be raised.

## Context

We heavily use Relay in our app that contains lots of screens, sub-screens, and independent components that have their own `useLazyLoadQuery()` in them. And it might happen that several components would fetch different slices of the same GQL record. I am aware of the main Relay guidance that there should be only 1 query per page, and everything else should be a component with its own fragment, but production reality is always something different. :/

Consider this example: list of entities (TODOs) + detail view of an entity (TODO). These two components are independent by routes, but have an overlap in data.
`React.StrictMode`, of course, and a very aggressive Relay Store option `gcReleaseBufferSize: 0` (for showcase purposes).

Normally on a MBP M2 things happen so fast that mostly there are no errors. But various TypeErrors reported in Sentry made us investigate. So I found some conditions in which Relay environment does not behave predictively from my point of view (or I don't understand something).

In a `fetchFn` for `RelayEnvironment` if there is a fictional delay placed more than ±400ms, opening a page with both list and detail view would sometimes end up in list view throwing an error because of missing data.
If bigger delays are set up, and - most importantly - different for different queries, then the list view always resolves in error because `useLazyLoadQuery()` of list view gets a re-render notification, but store does not return data for the entire list this time, only for a record which has its detail view open:

https://github.com/user-attachments/assets/3395252f-7007-4a75-9a4e-227990139fea

There is an excessive logging of everything what is happening, and right before re-rendering Relay logger reports `missing_expected_data.log` for most of the stuff in the list:

Image

## Question

Is this behavior expected? Or maybe there is something that I'm missing in the setup? Bumping `gcReleaseBufferSize` to some higher numbers (30-100) does not help.

## Resources

I've tried to include most of the stuff we have in production (such as `useSyncExternalStore` in the middle for storing current detail view ID, or the exact implementation of `missingFieldHandlers`) yet keep those parts minimal.

[Link to repo](https://github.com/Yelmuf/relay-demo) with reproduction and a test that simulates the above.

[Link to Codesandbox](https://codesandbox.io/p/github/Yelmuf/relay-demo/main).

Contributor guide

Open the contributing guide

Research direction

Start with the linked relay-demo reproduction and its test, then inspect the concurrent useLazyLoadQuery() behavior around RelayEnvironment and fetchFn delays. Reproduce the missing_expected_data.log and list-view failure under different query timings; done means the expected behavior is established and the underlying data-loss error is fixed or clearly documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.