Add dynamic flag to opt provided variables out of value memoization#5342
Add dynamic flag to opt provided variables out of value memoization#5342striedinger wants to merge 1 commit into
dynamic flag to opt provided variables out of value memoization#5342Conversation
Provided-variable providers are memoized process-wide: withProvidedVariables pins each provider's first return value in a module-level cache to enforce purity. On a server, where one process serves many requests/viewers, a provider that reads per-request state legitimately varies per request, which pins stale values and emits spurious purity warnings. Add an opt-in `dynamic?: boolean` on the provider object. When true, withProvidedVariables uses the freshly resolved value and skips both the cache and the warning; default behavior is unchanged. relay-typegen now emits an optional `dynamic?: boolean` on the generated provider type so a provider exporting it still typechecks against the exact object type. Docs, tests, and a fixture are included; generated artifacts and typegen snapshots regenerated.
|
Hi @striedinger! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
Summary
Provided-variable providers are memoized process-wide.
withProvidedVariablespins each provider's first return value in a module-level cache keyed by the
getfunction, to enforce purity. That's fine in a browser tab, but wrong on aserver, where one process serves many requests/viewers. A provider that reads
per-request state (auth/session, locale, experiment bucket) legitimately returns
different values per request, and today that causes two problems:
subsequent requests resolve with stale variables.
across requests:
Note the store/reader path (
RelayConcreteVariables.getOperationVariables)already resolves providers fresh per operation with no cache, so the two
resolution paths disagree for any non-pure provider.
This adds an opt-in
dynamic?: booleanto the provider object. Whendynamicis true,
withProvidedVariablesuses the freshly resolved value and skips boththe cache and the purity warning. Default behavior is unchanged.
dynamicis a runtime property of the provider module, so this needs no newGraphQL surface. It does require a small relay-compiler change: the generated
provider type is an exact object (
{ readonly get: () => T }), so the compilernow also emits an optional
readonly dynamic?: boolean. Without it, a.relayprovidermodule that exportsdynamicfails Flow ("exact objects do notaccept extra props").
Changes
relay-runtime/util/withProvidedVariables.js— bypass the memoization cache(and its warning) for
dynamicproviders.relay-runtime/util/RelayConcreteNode.js/.d.ts— addreadonly dynamic?: booleanto the provider type (Flow + TS).relay-typegen(write.rs) — emitdynamic?: booleanon the generatedprovider type; typegen snapshots and generated artifacts regenerated.
graphql-directives.mdx) — documentdynamicand add an example.provideDynamicValue.relayproviderfixture.Notes
get()is resolved on both the store path(
getOperationVariables) and the network path (withProvidedVariables); thisduplication is pre-existing. For
dynamicproviders it makes the two pathsmore consistent (both fresh) rather than less.
get()should remainconsistent within a single run.
Test Plan
yarn jest packages/relay-runtime/util/__tests__/withProvidedVariables-test.js— new "marked dynamic" test (fresh value each call, no warning) passes;
existing cache/warning tests unchanged.
yarn jest ProvidedVariable— all provided-variable suites pass (regeneratedartifacts are a types-only change).
yarn flow check— No errors.yarn prettier— clean.cargo fmtclean forwrite.rs;cargo test -p relay-typegenand thecompile_relay_artifactstargets pass against the blessed snapshots; fixturesregenerated via
UPDATE_SNAPSHOTS=1.