diegomura / react-pdf

📄 Create PDF files using React
https://react-pdf.org
MIT License
14.66k stars 1.16k forks source link

MaxListenersExceededWarning: Possible EventEmitter memory leak detected #2825

Open Torbraw opened 1 month ago

Torbraw commented 1 month ago

Describe the bug When trying to render multiple times the same pdf with renderToBuffer() in a loop in a Nest.js app (with express), I get the following warnings in the console. Note that all the render() methods yield the same error:

(node:41468) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 unhandledRejection listeners added to [process]. Use emitter.setMaxListeners() to increase limit
(Use 'node --trace-warnings ...' to show where the warning was created)
(node:41468) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 uncaughtException listeners added to [process]. Use emitter.setMaxListeners() to increase limit

If I add process.on('warning', e => console.warn(e.stack)); to have more infos here's the results:

MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 unhandledRejection listeners added to [process]. Use emitter.setMaxListeners() to increase limit
    at genericNodeError (node:internal/errors:984:15)
    at wrappedFn (node:internal/errors:538:14)
    at _addListener (node:events:593:17)
    at process.addListener (node:events:611:10)
    at loadAssembly (C:\Workspace\flexyb-pay\node_modules\yoga-layout\binaries\wasm-async-node.js:11:63)
    at Object.loadYoga (C:\Workspace\flexyb-pay\node_modules\yoga-layout\src\entrypoint\wasm-async-node.ts:25:29)
    at _callee$ (C:\Workspace\flexyb-pay\node_modules\@react-pdf\layout\lib\index.cjs:698:34)
    at tryCatch (C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:133:17)
    at Generator.next (C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\asyncToGenerator.js:3:17)
    at _next (C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\asyncToGenerator.js:17:9)
    at C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\asyncToGenerator.js:22:7
    at new Promise (<anonymous>)
    at C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\asyncToGenerator.js:14:12
    at loadYoga (C:\Workspace\flexyb-pay\node_modules\@react-pdf\layout\lib\index.cjs:718:17)
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 uncaughtException listeners added to [process]. Use emitter.setMaxListeners() to increase limit
    at genericNodeError (node:internal/errors:984:15)
    at wrappedFn (node:internal/errors:538:14)
    at _addListener (node:events:593:17)
    at process.addListener (node:events:611:10)
    at loadAssembly (C:\Workspace\flexyb-pay\node_modules\yoga-layout\binaries\wasm-async-node.js:11:9)
    at Object.loadYoga (C:\Workspace\flexyb-pay\node_modules\yoga-layout\src\entrypoint\wasm-async-node.ts:25:29)
    at _callee$ (C:\Workspace\flexyb-pay\node_modules\@react-pdf\layout\lib\index.cjs:698:34)
    at tryCatch (C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:133:17)
    at Generator.next (C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\asyncToGenerator.js:3:17)
    at _next (C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\asyncToGenerator.js:17:9)
    at C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\asyncToGenerator.js:22:7
    at new Promise (<anonymous>)
    at C:\Workspace\flexyb-pay\node_modules\@babel\runtime\helpers\asyncToGenerator.js:14:12
    at loadYoga (C:\Workspace\flexyb-pay\node_modules\@react-pdf\layout\lib\index.cjs:718:17)

To Reproduce Steps to reproduce the behavior including code snippet (if applies):

  1. Clone the following repository
  2. Run npm i & npm run start:dev
  3. Go to localhost:3000/api to see the swagger-ui
  4. Call the get endpoint and see the warnings in the console of your IDE

Expected behavior The eventEmitters should be disposed/close correctly and there should be no warnings.

Desktop (please complete the following information):

PatricioNG commented 1 month ago

Can confirm I've run into the same and went looking to see if I was the only one, seems like a potential memory leak 👀 On ^3.4.4 running on Node/Windows server 2019 on this end.

jhgeluk commented 1 month ago

Also experiencing this bug. This is my stack trace with "@react-pdf/renderer": "3.4.4"

(node:38795) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 uncaughtException listeners added to [process]. Use emitter.setMaxListeners() to increase limit
    at _addListener (node:events:592:17)
    at process.addListener (node:events:610:10)
    at loadAssembly (*REDACTED*/node_modules/yoga-layout/binaries/wasm-async-node.js:11:9)
    at Object.loadYoga (*REDACTED*/node_modules/yoga-layout/src/entrypoint/wasm-async-node.ts:25:29)
    at _callee$ (*REDACTED*/node_modules/@react-pdf/layout/lib/index.cjs:707:34)
    at tryCatch (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
    at Generator.next (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12
    at loadYoga (*REDACTED*/node_modules/@react-pdf/layout/lib/index.cjs:727:17)
    at _callee$ (*REDACTED*/node_modules/@react-pdf/layout/lib/index.cjs:738:18)
    at tryCatch (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
    at Generator.next (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12
    at resolveYoga (*REDACTED*/node_modules/@react-pdf/layout/lib/index.cjs:751:17)
    at _callee$ (*REDACTED*/node_modules/@react-pdf/fns/lib/index.cjs:74:23)
    at tryCatch (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
    at Generator.next (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12
    at Object.<anonymous> (*REDACTED*/node_modules/@react-pdf/fns/lib/index.cjs:90:19)
    at _callee$ (*REDACTED*/node_modules/@react-pdf/renderer/src/index.js:50:40)
    at tryCatch (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
    at Generator.next (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at apply (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12)
    at render (*REDACTED*/node_modules/@react-pdf/renderer/src/index.js:36:15)
    at _callee3$ (*REDACTED*/node_modules/@react-pdf/renderer/src/index.js:90:15)
    at tryCatch (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
    at Generator.next (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at Object.apply (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12)
    at Object.toBuffer (*REDACTED*/node_modules/@react-pdf/renderer/src/index.js:86:17)
    at _callee$ (*REDACTED*/node_modules/@react-pdf/renderer/src/node/renderTo.js:12:33)
(node:38795) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 unhandledRejection listeners added to [process]. Use emitter.setMaxListeners() to increase limit
    at _addListener (node:events:592:17)
    at process.addListener (node:events:610:10)
    at loadAssembly (*REDACTED*/node_modules/yoga-layout/binaries/wasm-async-node.js:11:63)
    at Object.loadYoga (*REDACTED*/node_modules/yoga-layout/src/entrypoint/wasm-async-node.ts:25:29)
    at _callee$ (*REDACTED*/node_modules/@react-pdf/layout/lib/index.cjs:707:34)
    at tryCatch (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
    at Generator.next (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12
    at loadYoga (*REDACTED*/node_modules/@react-pdf/layout/lib/index.cjs:727:17)
    at _callee$ (*REDACTED*/node_modules/@react-pdf/layout/lib/index.cjs:738:18)
    at tryCatch (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
    at Generator.next (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12
    at resolveYoga (*REDACTED*/node_modules/@react-pdf/layout/lib/index.cjs:751:17)
    at _callee$ (*REDACTED*/node_modules/@react-pdf/fns/lib/index.cjs:74:23)
    at tryCatch (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
    at Generator.next (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12
    at Object.<anonymous> (*REDACTED*/node_modules/@react-pdf/fns/lib/index.cjs:90:19)
    at Object.default (*REDACTED*/node_modules/@react-pdf/renderer/src/index.js:50:40)
    at _callee$ (*REDACTED*/node_modules/@react-pdf/renderer/src/index.js:50:40)
    at tryCatch (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
    at Generator.next (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at apply (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12)
    at render (*REDACTED*/node_modules/@react-pdf/renderer/src/index.js:36:15)
    at _callee3$ (*REDACTED*/node_modules/@react-pdf/renderer/src/index.js:90:15)
    at tryCatch (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:133:17)
    at Generator.next (*REDACTED*/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at *REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at Object.apply (*REDACTED*/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12)
    at Object.toBuffer (*REDACTED*/node_modules/@react-pdf/renderer/src/index.js:86:17)
    at _callee$ (*REDACTED*/node_modules/@react-pdf/renderer/src/node/renderTo.js:12:33)
leiteszeke commented 1 month ago

Exactly the same issue. I have been receiving this in the last 3 months at least.

I am using "@react-pdf/renderer": "^3.4.4"

(node:98733) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 uncaughtException listeners added to [process]. Use emitter.setMaxListeners() to increase limit
    at _addListener (node:events:591:17)
    at process.addListener (node:events:609:10)
    at /var/www/daruma/graphql/node_modules/yoga-layout/binaries/wasm-async-node.js:11:9
    at Object.loadYoga (/var/www/daruma/graphql/node_modules/yoga-layout/src/entrypoint/wasm-async-node.js:35:43)
    at _callee$ (/var/www/daruma/graphql/node_modules/@react-pdf/layout/lib/index.cjs:707:34)
    at tryCatch (/var/www/daruma/graphql/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:44:17)
    at Generator.<anonymous> (/var/www/daruma/graphql/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:125:22)
    at Generator.next (/var/www/daruma/graphql/node_modules/@babel/runtime/helpers/regeneratorRuntime.js:69:21)
    at asyncGeneratorStep (/var/www/daruma/graphql/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (/var/www/daruma/graphql/node_modules/@babel/runtime/helpers/asyncToGenerator.js:22:9)
    at /var/www/daruma/graphql/node_modules/@babel/runtime/helpers/asyncToGenerator.js:27:7
    at new Promise (<anonymous>)
    at /var/www/daruma/graphql/node_modules/@babel/runtime/helpers/asyncToGenerator.js:19:12
    at loadYoga (/var/www/daruma/graphql/node_modules/@react-pdf/layout/lib/index.cjs:727:17)
    at _callee$ (/var/www/daruma/graphql/node_modules/@react-pdf/layout/lib/index.cjs:738:18)
karlandindrakryggen commented 1 month ago

I've noticed the same issue. I'm not sure, but suspect that it can have been introduced in the switch from @react-pdf/yoga to yoga-layout. At least I get the dependency chains below when making a fresh installation with the different versions, and it's only with @react-pdf/renderer@2.1.1 (the latest version with @react-pdf/yoga) that work without the memory issue in my tests.

One clue might be that the yoga-layout readme says that you must call config.free()/node.free()?

2.1.1

└─┬ @react-pdf/renderer@2.1.1
  └─┬ @react-pdf/layout@2.1.1
    └── @react-pdf/yoga@2.0.4

2.1.2

└─┬ @react-pdf/renderer@2.1.2
  └─┬ @react-pdf/layout@3.12.1
    └── yoga-layout@2.0.1

latest (3.4.4)

└─┬ @react-pdf/renderer@3.4.4
  └─┬ @react-pdf/layout@3.12.1
    └── yoga-layout@2.0.1

Update: I've created a simple example that generates 1000 pdf documents and prints memory usage: https://github.com/karlandindrakryggen/react-pdf-memory-issue. I've included printouts for different versions of @react-pdf/renderer in the README.

michalprikryl commented 1 month ago

We have the same issue at the nodejs (express) environment.

(node:21532) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 uncaughtException listeners added to [process]. Use emitter.setMaxListeners() to increase limit at _addListener (node:events:588:17) at process.addListener (node:events:606:10) at C:\node_modules\yoga-layout\binaries\wasm-async-node.js:11:9 at Module.loadYoga (C:\node_modules\yoga-layout\src\entrypoint\wasm-async-node.js:35:43) at _callee$ (file:///C:/node_modules/@react-pdf/layout/lib/index.js:672:23) at tryCatch (C:\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:45:16) at Generator.<anonymous> (C:\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:133:17) at Generator.next (C:\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:74:21) at asyncGeneratorStep (C:\node_modules\@babel\runtime\helpers\asyncToGenerator.js:3:17)

vipuljbhikadiya commented 1 month ago

I've noticed the same issue. I'm not sure, but suspect that it can have been introduced in the switch from @react-pdf/yoga to yoga-layout. At least I get the dependency chains below when making a fresh installation with the different versions, and it's only with @react-pdf/renderer@2.1.1 (the latest version with @react-pdf/yoga) that work without the memory issue in my tests.

One clue might be that the yoga-layout readme says that you must call config.free()/node.free()?

2.1.1

└─┬ @react-pdf/renderer@2.1.1
  └─┬ @react-pdf/layout@2.1.1
    └── @react-pdf/yoga@2.0.4

2.1.2

└─┬ @react-pdf/renderer@2.1.2
  └─┬ @react-pdf/layout@3.12.1
    └── yoga-layout@2.0.1

latest (3.4.4)

└─┬ @react-pdf/renderer@3.4.4
  └─┬ @react-pdf/layout@3.12.1
    └── yoga-layout@2.0.1

Update: I've created a simple example that generates 1000 pdf documents and prints memory usage: https://github.com/karlandindrakryggen/react-pdf-memory-issue. I've included printouts for different versions of @react-pdf/renderer in the README.

HI are you able to trace anything we are facing same issue when we are generating PDF more then 2000 pages.

karlandindrakryggen commented 1 month ago

I've noticed the same issue. I'm not sure, but suspect that it can have been introduced in the switch from @react-pdf/yoga to yoga-layout. At least I get the dependency chains below when making a fresh installation with the different versions, and it's only with @react-pdf/renderer@2.1.1 (the latest version with @react-pdf/yoga) that work without the memory issue in my tests. One clue might be that the yoga-layout readme says that you must call config.free()/node.free()? 2.1.1

└─┬ @react-pdf/renderer@2.1.1
  └─┬ @react-pdf/layout@2.1.1
    └── @react-pdf/yoga@2.0.4

2.1.2

└─┬ @react-pdf/renderer@2.1.2
  └─┬ @react-pdf/layout@3.12.1
    └── yoga-layout@2.0.1

latest (3.4.4)

└─┬ @react-pdf/renderer@3.4.4
  └─┬ @react-pdf/layout@3.12.1
    └── yoga-layout@2.0.1

Update: I've created a simple example that generates 1000 pdf documents and prints memory usage: https://github.com/karlandindrakryggen/react-pdf-memory-issue. I've included printouts for different versions of @react-pdf/renderer in the README.

HI are you able to trace anything we are facing same issue when we are generating PDF more then 2000 pages.

Hi! No, unfortunately I have not looked into this anymore.

AminArjiEpitech commented 2 days ago

Same issue here, i'll just dump my node trace and comment so i can get an update when there's one

(node:20944) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 uncaughtException listeners added to [process]. Use emitter.setMaxListeners() to increase limit
    at _addListener (node:events:587:17)
    at process.addListener (node:events:605:10)
    at loadAssembly (C:\Users\Amin\Code\Deepsy-pdf\node_modules\yoga-layout\binaries\wasm-async-node.js:11:9)
    at Object.loadYoga (C:\Users\Amin\Code\Deepsy-pdf\node_modules\yoga-layout\src\entrypoint\wasm-async-node.ts:25:29)
    at _callee$ (C:\Users\Amin\Code\Deepsy-pdf\node_modules\@react-pdf\layout\lib\index.cjs:707:34)
    at tryCatch (C:\Users\Amin\Code\Deepsy-pdf\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:45:16)
    at Generator.<anonymous> (C:\Users\Amin\Code\Deepsy-pdf\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:133:17)
    at Generator.next (C:\Users\Amin\Code\Deepsy-pdf\node_modules\@babel\runtime\helpers\regeneratorRuntime.js:74:21)
    at asyncGeneratorStep (C:\Users\Amin\Code\Deepsy-pdf\node_modules\@babel\runtime\helpers\asyncToGenerator.js:3:17)
    at _next (C:\Users\Amin\Code\Deepsy-pdf\node_modules\@babel\runtime\helpers\asyncToGenerator.js:17:9)
MarcoRodasW commented 1 day ago

Hi, is there a solution for this issue? Any workaround?

jhgeluk commented 1 day ago

Also related to: #2848

I came across this PR, that might be related: #2711, but not a 100% sure.

For anyone following this issue, as a temporary fix downgrade to the any of the following packages you may use:

@react-pdf/layout@3.9.0 @react-pdf/renderer@3.2.0

And make sure to pin it in your package.json

Saw this temporary fix from @moishinetzer at #2589

And in addition to pinning those exact versions, I also had to add this to my overrides in the package.json: "@react-pdf/textkit": "4.2.1"

Now, what I noticed with this fix is that the used memory slightly decreases. But the problem is not fully gone yet. Because for every PDF we create, the memory keeps increasing, and does not drop back down anymore.

jhgeluk commented 1 day ago

I've noticed the same issue. I'm not sure, but suspect that it can have been introduced in the switch from @react-pdf/yoga to yoga-layout. At least I get the dependency chains below when making a fresh installation with the different versions, and it's only with @react-pdf/renderer@2.1.1 (the latest version with @react-pdf/yoga) that work without the memory issue in my tests.

One clue might be that the yoga-layout readme says that you must call config.free()/node.free()?

2.1.1

└─┬ @react-pdf/renderer@2.1.1
  └─┬ @react-pdf/layout@2.1.1
    └── @react-pdf/yoga@2.0.4

2.1.2

└─┬ @react-pdf/renderer@2.1.2
  └─┬ @react-pdf/layout@3.12.1
    └── yoga-layout@2.0.1

latest (3.4.4)

└─┬ @react-pdf/renderer@3.4.4
  └─┬ @react-pdf/layout@3.12.1
    └── yoga-layout@2.0.1

Update: I've created a simple example that generates 1000 pdf documents and prints memory usage: https://github.com/karlandindrakryggen/react-pdf-memory-issue. I've included printouts for different versions of @react-pdf/renderer in the README.

We can always try to add it, where would you reckon this config.free() code should go?

In https://github.com/diegomura/react-pdf/blob/master/packages/layout/src/yoga/index.js or https://github.com/diegomura/react-pdf/blob/master/packages/layout/src/steps/resolveYoga.js?

@karlandindrakryggen

AminArjiEpitech commented 16 hours ago

Edit : I just tested, this still causes memory leaks, please ignore.

Not a solution but a temporary workaround until this is resolved, you might not like it.

  1. Create a folder where you wish and save every rendered pdf's in there.
  2. Periodically clean the folder's content with conditions, in my case after every request i check the size of the folder and delete the oldest file, or simply delete every file older than an hour.

Here's the code i've used in a nodejs server :

const pdfFolder = path.join(__dirname, 'generatedPdfs');

if (!fs.existsSync(pdfFolder)) {
    fs.mkdirSync(pdfFolder);
}

// Clean folder on process startup
const cleanUpFolder = () => {
    fs.readdir(pdfFolder, (err, files) => {
        if (err) return console.error("Error reading directory:", err);
        files.forEach(file => fs.unlinkSync(path.join(pdfFolder, file)));
    });
};

cleanUpFolder();

...

// Call this to clean conditionnaly
const deleteOldFiles = () => {
    fs.readdir(pdfFolder, (err, files) => {
        if (err) return console.error("Error reading directory:", err);

        const fileStats = files.map(file => {
            const filePath = path.join(pdfFolder, file);
            return { file, time: fs.statSync(filePath).mtime };
        });

        const oneHourAgo = new Date(Date.now() - 3600000);
        fileStats.forEach(({ file, time }) => {
            if (time < oneHourAgo) {
                fs.unlinkSync(path.join(pdfFolder, file));
            }
        });

        if (fileStats.length > 20) {
            fileStats.sort((a, b) => a.time - b.time); // TODO: Try
            fileStats.slice(0, fileStats.length - 20).forEach(({ file }) => {
                fs.unlinkSync(path.join(pdfFolder, file));
            });
        }
    });
};

Also i suggest checking the filename before generating the pdf, in case you've already generated one you can directly send it.

jhgeluk commented 13 hours ago

Not a solution but a temporary workaround until this is resolved, you might not like it.

  1. Create a folder where you wish and save every rendered pdf's in there.
  2. Periodically clean the folder's content with conditions, in my case after every request i check the size of the folder and delete the oldest file, or simply delete every file older than an hour.

Here's the code i've used in a nodejs server :

const pdfFolder = path.join(__dirname, 'generatedPdfs');

if (!fs.existsSync(pdfFolder)) {
    fs.mkdirSync(pdfFolder);
}

// Clean folder on process startup
const cleanUpFolder = () => {
    fs.readdir(pdfFolder, (err, files) => {
        if (err) return console.error("Error reading directory:", err);
        files.forEach(file => fs.unlinkSync(path.join(pdfFolder, file)));
    });
};

cleanUpFolder();

...

// Call this to clean conditionnaly
const deleteOldFiles = () => {
    fs.readdir(pdfFolder, (err, files) => {
        if (err) return console.error("Error reading directory:", err);

        const fileStats = files.map(file => {
            const filePath = path.join(pdfFolder, file);
            return { file, time: fs.statSync(filePath).mtime };
        });

        const oneHourAgo = new Date(Date.now() - 3600000);
        fileStats.forEach(({ file, time }) => {
            if (time < oneHourAgo) {
                fs.unlinkSync(path.join(pdfFolder, file));
            }
        });

        if (fileStats.length > 20) {
            fileStats.sort((a, b) => a.time - b.time); // TODO: Try
            fileStats.slice(0, fileStats.length - 20).forEach(({ file }) => {
                fs.unlinkSync(path.join(pdfFolder, file));
            });
        }
    });
};

Also i suggest checking the filename before generating the pdf, in case you've already generated one you can directly send it.

That's quite a good temporary work-around for this issue. Do you use renderToFile() instead of renderToStream()?

Does renderToFile() not cause any memory leaks? @AminArjiEpitech

AminArjiEpitech commented 13 hours ago

@jhgeluk Nevermind, looks like this is not a workaround at all !

I just did some tests in my previous code, and i still get the exact same warning, only instead of 11 emitters, it's now 15. (node:133390) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 16 uncaughtException listeners added to [process]. MaxListeners is 15. Use emitter.setMaxListeners() to increase limit

I used both ReactPDF.render() and renderToFile() to test this, and i still get the warning.

Looks like the only solution to really workaround this is to do what i've done, using babel and transforming your normal react code into a script. This would eliminate all possibility of a memory leak, but the problem with this solution is that it is more cpu and ram expensive and may not be adapted to all, it works for me because i will most likely never have more than 1-2 renders per minute.

jhgeluk commented 10 hours ago

@jhgeluk Nevermind, looks like this is not a workaround at all !

I just did some tests in my previous code, and i still get the exact same warning, only instead of 11 emitters, it's now 15.

(node:133390) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 16 uncaughtException listeners added to [process]. MaxListeners is 15. Use emitter.setMaxListeners() to increase limit

I used both ReactPDF.render() and renderToFile() to test this, and i still get the warning.

Looks like the only solution to really workaround this is to do what i've done, using babel and transforming your normal react code into a script.

This would eliminate all possibility of a memory leak, but the problem with this solution is that it is more cpu and ram expensive and may not be adapted to all, it works for me because i will most likely never have more than 1-2 renders per minute.

@AminArjiEpitech do you have some more details about how you fixed it? Would really appreciate it! We're fine if it's a bit more expensive on the ram/cpu. As long as it doesnt keep accumulating ram, which will result in a crash.