facebook / yoga

Yoga is an embeddable layout engine targeting web standards.

Home Page:https://yogalayout.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RuntimeError with WebAssembly in @react-pdf/yoga on Node.js Server

gino8080 opened this issue · comments

Hello,

I've encountered a critical issue while using @react-pdf/renderer in a Node.js Express server environment. The server crashes with a RuntimeError related to WebAssembly memory allocation when attempting to generate PDFs. The error message is as follows:

RuntimeError: Aborted(RangeError: WebAssembly.instantiate(): Out of memory: wasm memory). Build with -sASSERTIONS for more info.
    at w (/usr/app/node_modules/yoga-layout/binaries/wasm-async-node.js:14:73)
    at /usr/app/node_modules/yoga-layout/binaries/wasm-async-node.js:62:60

This error suggests that the WebAssembly module within yoga-layout, which is a dependency of @react-pdf/renderer, is running out of memory.

To Reproduce

  1. Set up a basic Express server that uses @react-pdf/renderer to generate PDFs.
  2. Trigger the PDF generation endpoint with the necessary data.
  3. The server crashes with the above RuntimeError after a few successful PDF generations.
    Expected Behavior:

The PDF generation should complete successfully without causing a server crash or running out of WebAssembly memory.

Actual Behavior:

The server crashes with a RuntimeError indicating that WebAssembly ran out of memory.

Additional Context:

The issue seems to occur after generating multiple PDFs, suggesting a potential memory leak or insufficient memory allocation for WebAssembly in the yoga-layout module.
Reducing the complexity of the PDF layout temporarily mitigates the issue but does not solve it entirely.
I would appreciate any insights or suggestions on how to resolve this issue. If there are any known workarounds or if additional information is needed, please let me know.

Environment:

Node.js version: v16.18.1
Express version: ^4.18.2
@react-pdf/layout": "3.10.3",
@react-pdf/renderer": "3.3.4",
Operating System: docker image

Thank you for your time and assistance.

This is going to be hard to diagnose without more information about the usage.

The Yoga wasm binary allows heap growth (

"SHELL:-s ALLOW_MEMORY_GROWTH=1"
) and provides methods to free nodes/configs.

Without knowing more, out of memory seems like the consuming library might not be freeing resources, or that there is an irregularly large tree.

Not sure if this is relevant, but in my (browser based) benchmarking scripts where I was constructing, measuring and then destructing Yoga trees in a loop, I was hitting a similar crash. It took quite high iteration count (>10000) to hit it, but it was with a script that in theory shouldn't have increased heap size at all. This also occurred with a similar Taffy-based benchmark at similar iteration counts.

It could perhaps be due to heap fragmentation? Or immaturity of WASM implementations? Although I must admit that I haven't investigated this thoroughly enough to rule out user error.

As a workaround, if this is only occurring after repeated PDF generation, then you could try the following steps (in order):

  • Catch the exception
  • Deinitialise the WASM module
  • Reinitialise the WASM module
  • Retry your call into Yoga

I took a quick look at this, and other issues running into it: vercel/next.js#51870

I missed that this error happens during WASM environment instantiation. So, this error indicates that the WASM is being loaded into a new environment, and Node doesn't have enough memory to do that.

I am wondering if this scenario is somehow doing this loading more than once, or if maybe multiple processes are doing this, and running out of memory.

I went to double check if we have documented guarantees from Emscripten module that it is only loaded once on load call, but couldn't quickly verify. We are pushing out Yoga 3.0 now, which will cache the instance regardless.