From 8ecc536e206fe5ffec1713874ae091a37262d133 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Wed, 23 Feb 2022 00:10:22 -0500 Subject: [PATCH] Re-add reentrancy avoidance I removed the equivalency of this in #22446. However, I didn't fully understand the intended semantics of the spec but I understand this better now. The spec is not actually recursive. It won't call pull again inside of a pull. It might not call it inside startWork neither which the original issue avoided. However, it will call pull if you enqueue to the controller without filling up the desired size outside any call. We could avoid that by returning a Promise from pull that we wait to resolve until we've performed all our pending tasks. That would be the more idiomatic solution. That's a bit more involved but since we know understand it, we can readd the reentrancy hack since we have an easy place to detect it. If anything, it should probably throw or log here otherwise. I believe this fixes #22772. This includes the test from #22889 but should ideally have one for Fizz. --- packages/react-server/src/ReactFizzServer.js | 4 ++++ packages/react-server/src/ReactFlightServer.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/react-server/src/ReactFizzServer.js b/packages/react-server/src/ReactFizzServer.js index e46aee9a45cd2..39fcdf3168205 100644 --- a/packages/react-server/src/ReactFizzServer.js +++ b/packages/react-server/src/ReactFizzServer.js @@ -1950,6 +1950,10 @@ export function startFlowing(request: Request, destination: Destination): void { if (request.status === CLOSED) { return; } + if (request.destination !== null) { + // We're already flowing. + return; + } request.destination = destination; try { flushCompletedQueues(request, destination); diff --git a/packages/react-server/src/ReactFlightServer.js b/packages/react-server/src/ReactFlightServer.js index 052fa730fd91e..5ad7ed2ea041c 100644 --- a/packages/react-server/src/ReactFlightServer.js +++ b/packages/react-server/src/ReactFlightServer.js @@ -790,6 +790,10 @@ export function startFlowing(request: Request, destination: Destination): void { if (request.status === CLOSED) { return; } + if (request.destination !== null) { + // We're already flowing. + return; + } request.destination = destination; try { flushCompletedChunks(request, destination);