Repository: vercel/next.js
File: packages/next/src/server/app-render/app-render.tsx (TypeScript)

Code before:
        initialAbandonController.abort()
      } else {
        initialStageController.advanceStage(RenderStage.Dynamic)
      }
    }
  )

  if (initialStageController.currentStage !== RenderStage.Abandoned) {
    // No cache misses. We can use the result as-is.
    return {
      stream: initialStreamResult.stream,
      accumulatedChunksPromise: initialStreamResult.accumulatedChunksPromise,
      staticInterruptReason: initialStageController.getStaticInterruptReason(),
      runtimeInterruptReason:
        initialStageController.getRuntimeInterruptReason(),
      startTime,
      staticStageEndTime: initialStageController.getStaticStageEndTime(),
      runtimeStageEndTime: initialStageController.getRuntimeStageEndTime(),
      debugChannel,
      requestStore,
    }
  } else {
    // The render was abandoned due to cache misses.
    // Clean up the unused streams to avoid leaking resources.
    initialStreamResult.stream.cancel()
    initialStreamResult.accumulatedChunksPromise.catch(() => {})
  }

  if (process.env.__NEXT_DEV_SERVER && setCacheStatus) {
    setCacheStatus('filling', htmlRequestId)
  }

  // Cache miss. We will use the initial render to fill caches, and discard its result.
  // Then, we can render again with warm caches.

  // TODO(restart-on-cache-miss):
  // This might end up waiting for more caches than strictly necessary,
  // because we can't abort the render yet, and we'll let runtime/dynamic APIs resolve.
  // Ideally we'd only wait for caches that are needed in the static stage.
  // This will be optimized in the future by not allowing runtime/dynamic APIs to resolve.

  await cacheSignal.cacheReady()
  initialReactController.abort()

  //===============================================
  // Final render (restarted)
  //===============================================

  // The initial render acted as a prospective render to warm the caches.
  requestStore = createRequestStore()


Review comment (suggestion):
nit: seems nicer to do this (catch first, then trigger a potential error). i guess this works because of microtaskiness but it reads weird
```suggestion
    initialStreamResult.accumulatedChunksPromise.catch(() => {})
    initialStreamResult.stream.cancel()
```

also don't we need to cancel the teed stream we're using for accumulating as well?

> To cancel the stream you then need to cancel both resulting branches.
> https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/tee

Code after:
      if (initialAbandonController.signal.aborted === true) {
        return
      } else if (cacheSignal.hasPendingReads()) {
        initialAbandonController.abort()
      } else {
        initialStageController.advanceStage(RenderStage.Runtime)
      }
    },
    () => {
      if (initialAbandonController.signal.aborted === true) {
        return
      } else if (cacheSignal.hasPendingReads()) {
        initialAbandonController.abort()
      } else {
        initialStageController.advanceStage(RenderStage.Dynamic)
      }
    }
  )

  if (initialStageController.currentStage !== RenderStage.Abandoned) {
    // No cache misses. We can use the result as-is.
    return {
      stream: initialStreamResult.stream,
      accumulatedChunksPromise: initialStreamResult.accumulatedChunksPromise,
      staticInterruptReason: initialStageController.getStaticInterruptReason(),
      runtimeInterruptReason:
        initialStageController.getRuntimeInterruptReason(),
      startTime,
      staticStageEndTime: initialStageController.getStaticStageEndTime(),
      runtimeStageEndTime: initialStageController.getRuntimeStageEndTime(),
      debugChannel,
      requestStore,
    }
  }

  if (process.env.__NEXT_DEV_SERVER && setCacheStatus) {
    setCacheStatus('filling', htmlRequestId)
  }

  // Cache miss. We will use the initial render to fill caches, and discard its result.
  // Then, we can render again with warm caches.

  // TODO(restart-on-cache-miss):
  // This might end up waiting for more caches than strictly necessary,
  // because we can't abort the render yet, and we'll let runtime/dynamic APIs resolve.
  // Ideally we'd only wait for caches that are needed in the static stage.
  // This will be optimized in the future by not allowing runtime/dynamic APIs to resolve.

  await cacheSignal.cacheReady()
  initialReactController.abort()