-
Notifications
You must be signed in to change notification settings - Fork 473
Description
Describe the bug
Hi everyone!
I'm using @urql/vue a lot in Nuxt 3 and 4, and I've noticed there's a memory leak on the Nuxt server when awaiting the useQuery.
My suspicion is that there's something wrong with wonka (or how it's handled), where the "await" in await useQuery() makes some observables remain stuck in memory forever.
I've created a minimal reproduction with both Nuxt 3 and 4, only adding the urql plugin and the PokeAPI to test API calls.
There, you'll find the steps to reproduce the leak and debug with VSCode:
- Open
nuxt-3ornuxt-4with VSCode. - Install the dependencies with
pnpm i. - Open the Run and debug section and start
Build & Preview, which will build and run in "production" mode. - After Nuxt has built and started the server, expand "Call stack" and select the more nested item (
nuxt.mjs->index.mjs). - Below, in "Realtime performance", select all items.
- Open
localhost:3000and keep refreshing the page many times. To be faster, in Chrome you can select the URL bar and presscmd + entermany times (or keep pressing them) to open new pages and trigger many API calls. - Now you should be able to see the memory leak, where the Resident Set Size is very high, and becomes higher and higher when you trigger many API calls simultaneously. It's also much higher than Heap Total.
- If you remove
awaitfrom theuseQuery, the leak will not occur.
You should see something like this:
If you keep opening (or refreshing) hundreds of tabs, the leak can easily go to ~200/300mb. If you stop for a while, the leak might disappear, but in our production scenario this might never happen.
We're using it in production, and we have around ~20/30 requests per second (rarely 0-10 req/s), and with this leak our memory can easily reach ~500mb in a couple of days.
As a workaround, we've currently removing await from the most triggered useQuery.
What do you think about it? Is there a way to fix it?
I'll be glad to help!
These are the results using clinic doctor: it seems like the event loop is accumulating, as well as the Resident Set Size.
Debugging page localhost:3000/ (fetching list data):
clinic doctor --on-port 'autocannon -c 5 -a 100 localhost:3000' -- node .output/server/index.mjs

Debugging page localhost:3000/{id} (fetching single pokemon data):
clinic doctor --on-port 'autocannon -c 5 -a 100 localhost:3000/1' -- node .output/server/index.mjs

Observations:
- List Data (
/): The response payload is only~43kb, but the memory leak quickly reaches~400mbunder load. - Single Item Data: The response payload is just
~1kb, and the leak still increases linearly, reaching~150mb.
The nature of the leak might be related to how arrays and nested arrays/objects (which are abundant in the list data) are processed. The issue could also be related to a wrong cleanup process when URQL checks or parses document fields, such as __typenames.
Reproduction
https://github.com/gianlucadifrancesco/urql-server-mem-leak-nuxt
Urql version
@urql/vue: v2.0.0
Validations
- I can confirm that this is a bug report, and not a feature request, RFC, question, or discussion, for which GitHub Discussions should be used
- Read the docs.
- Follow our Code of Conduct
