Skip to content
This repository was archived by the owner on Jan 1, 2025. It is now read-only.

Add flag to skip circular dependency detection #2214

Merged

Conversation

RyanHoldren
Copy link
Contributor

Summary:
I discovered a bug in detectCircularDependencies() where it may erroneously detect a circular dependency when graphQLQueryEffect() is used. It arises from the fact that we are using a global stack to keep track of which Atom/Selectors have been visited.

From the stack trace, I think I've figured out what is happening...

  1. There are a bunch of selectorGet() calls to load dependencies.
  2. This calls detectCircularDependencies() several times and a bunch of keys get added to the dependencyStack, as you would expect. So far, everything looks good.
  3. Then, because it is a nested dependency, we load an Atom that has a graphQLQueryEffect().
  4. The graphQLQueryEffect() subscribes to a RelayObservable.The act of subscribing schedules a task using the RelayFBScheduler.
  5. The schedule invokes flushSyncCallbacks() in ReactDOM.
  6. Which calls renderWithHooks() in ReactDOM.
  7. Which renders a component that calls useRecoilValue().
  8. We then end up back in detectCircularDependencies(), which is where we fail because the dependencyStack already includes the keys of all those previous Selectors and Atoms up to and including the Atom with the graphQLQueryEffect().

This change adds a flag prop named skipCircularDependencyDetection_DANGEROUS to <RecoilRoot>, which is propagated down to the Store. If this flag is set to true then detectCircularDependencies() is bypassed.

This is obviously less than ideal. I think we can all agree that a fix for detectCircularDependencies() would be a much better solution. I am under the impression that, that will be a major refactor though, since it will require changing dependencyStack to be non-global and passing it all around. This flag will at least mitigate the bug until a more proper solution can be implemented. It should be very easy to back it out once that happens.

Differential Revision: D44563103

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported labels Apr 13, 2023
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D44563103

@itamark
Copy link

itamark commented Apr 14, 2023

@RyanHoldren I think the failed check means you need to separate the ICSP and fbonly files out of the diff connected to this into a separate diff.

@RyanHoldren
Copy link
Contributor Author

I think it's okay. Doesn't it just mean that this pull request can't be merged via GitHub but must be shipped via Phabricator?

This Pull Request is synced with a Phabricator Diff that has internal-only changes. It is not safe to land directly on GitHub

…2214)

Summary:
Pull Request resolved: facebookexperimental#2214

I discovered a bug in `detectCircularDependencies()` where it may erroneously detect a circular dependency when `graphQLQueryEffect()` is used. It arises from the fact that we are using a global stack to keep track of which Atom/Selectors have been *visited*.

From the stack trace, I think I've figured out what is happening...
1) There are a bunch of `selectorGet()` calls to load dependencies.
2) This calls `detectCircularDependencies()` several times and a bunch of keys get added to the `dependencyStack`, as you would expect. So far, everything looks good.
3) Then, because it is a nested dependency, we load an Atom that has a `graphQLQueryEffect()`.
4) The `graphQLQueryEffect()` subscribes to a `RelayObservable`.The act of subscribing schedules a task using the `RelayFBScheduler`.
5) The schedule invokes `flushSyncCallbacks()` in ReactDOM.
6) Which calls `renderWithHooks()` in ReactDOM.
7) Which renders a component that calls `useRecoilValue()`.
8) We then end up back in `detectCircularDependencies()`, which is where we fail because the `dependencyStack` already includes the keys of all those previous Selectors and Atoms up to and including the Atom with the `graphQLQueryEffect()`.

This change adds a flag prop named `skipCircularDependencyDetection_DANGEROUS` to `<RecoilRoot>`, which is propagated down to the `Store`. If this flag is set to `true` then `detectCircularDependencies()` is bypassed.

This is obviously *less than ideal*. I think we can all agree that a fix for `detectCircularDependencies()` would be a much better solution. I am under the impression that, that will be a major refactor though, since it will require changing `dependencyStack` to be non-global and passing it all around. This flag will at least mitigate the bug until a more proper solution can be implemented. It should be very easy to back it out once that happens.

Differential Revision: D44563103

fbshipit-source-id: b396ad068b5dc511664d204e326086cc6b8af29c
@facebook-github-bot
Copy link
Contributor

This pull request was exported from Phabricator. Differential Revision: D44563103

@facebook-github-bot facebook-github-bot merged commit ec32a16 into facebookexperimental:main Apr 21, 2023
eagle2722 added a commit to eagle2722/Recoil that referenced this pull request Sep 21, 2024
Differential Revision: D44563103

Pull Request resolved: facebookexperimental/Recoil#2214
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants