thomasdondorf / puppeteer-cluster

Puppeteer Pool, run a cluster of instances in parallel
MIT License
3.2k stars 307 forks source link

Bug: No way to handle `UnhandledPromiseRejectionWarning` inside `cluster.work` #502

Open mhassan1 opened 1 year ago

mhassan1 commented 1 year ago

When the Promise returned by doWork here is rejected, we end up with an UnhandledPromiseRejectionWarning, which we can only deal with using a global process.on('unhandledRejection', ...) listener. There should be a better way for consumers to handle this error; maybe cluster should emit a clustererror event (or an error event, since it may be fatal), in this case.

I would be happy to contribute a fix, once we have an approach.

To reproduce:

const { Cluster } = require('puppeteer-cluster')

Cluster.launch({
  puppeteerOptions: {
    args: [
      '--single-process'
    ]
  },
}).then(cluster => {
  cluster.queue(async () => {})
})

NOTE: This reproduces on my Mac because the --single-process flag prevents Chromium from starting up. YMMV.

Actual output: An UnhandledPromiseRejectionWarning is emitted by the process, and the process exits:

Error: Unable to get browser page
    at Worker.<anonymous> (/puppeteer-cluster/node_modules/puppeteer-cluster/dist/Worker.js:41:31)
    at Generator.next (<anonymous>)
    at fulfilled (/puppeteer-cluster/node_modules/puppeteer-cluster/dist/Worker.js:5:58)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Node.js v18.12.1

Process finished with exit code 1

Expected output: An event is emitted by cluster, and no UnhandledPromiseRejectionWarning is emitted by the process

Related: https://github.com/thomasdondorf/puppeteer-cluster/issues/323

drizzef commented 1 year ago

im also facing the same issue.

zhaow-de commented 1 year ago

I can confirm the symptom. The roor cause seems like at https://github.com/thomasdondorf/puppeteer-cluster/blob/b5b098aed84b8d2c170b3f9d0ac050f53582df45/src/Cluster.ts#L238, the SetTimeout made Cluster.doWork run in the event loop scheduled as macro tasks. Therefore, any error rejects Cluster.doWork does not populate to Cluster.work and onward, which leads to the unhandeld rejection warning.

yangguangwuwu commented 10 months ago

me too

yangguangwuwu commented 10 months ago

throw new Error('Unable to get browser page'); ^

Error: Unable to get browser page at Worker. (/data/node_modules/puppeteer-cluster/dist/Worker.js:41:31) at Generator.next () at fulfilled (/data/node_modules/puppeteer-cluster/dist/Worker.js:5:58) at processTicksAndRejections (node:internal/process/task_queues:96:5)

yangguangwuwu commented 10 months ago

delete --single-process
run ok It is possible that puppeteer-cluster relies on multiple processes of browser instances.