Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

loadingTask.destroy() throws worker exception #11595

Closed
zmagyar opened this issue Feb 13, 2020 · 8 comments
Closed

loadingTask.destroy() throws worker exception #11595

zmagyar opened this issue Feb 13, 2020 · 8 comments

Comments

@zmagyar
Copy link

zmagyar commented Feb 13, 2020

I'm displaying a progress bar on document loading with a Cancel button to give a chance to the user to abort the download. If I understood correctly based on #6546 calling destroy() on the loading task is the correct way to do it. But that throws an exception in the worker what I even not able to catch anywhere.

Configuration:

  • Web browser and its version: Chrome 80.0.3987, Safari 13.0.5 (15608.5.11)
  • Operating system and its version: MacOS 10.15.3
  • PDF.js version: v2.3.200 (same in 2.2.228)
  • Is a browser extension: no

Steps to reproduce the problem:

  1. Call loadingTask.destroy() before getDocument resolves

What is the expected behavior? (add screenshot)
Worker should stop without exception

What went wrong? (add screenshot)
Try https://jsfiddle.net/zmagyar/uLnqk1m5/1/#
Console says:
(index):76 Error: Worker was destroyed
at terminateEarly (api.js:1781)
at api.js:1827
at Worker.MessageHandler._onComObjOnMessage (message_handler.js:147)

@Snuffleupagus
Copy link
Collaborator

Snuffleupagus commented Feb 13, 2020

If I understood correctly based on #6546 calling destroy() on the loading task is the correct way to do it. But that throws an exception in the worker what I even not able to catch anywhere.

Are you sure about the "throws an exception" part, since what should be happening is that loadingTask.promise simply contains a rejected Promise (with Worker was destroyed as its message)?

Worker should stop without exception

What went wrong? (add screenshot)
Try https://jsfiddle.net/zmagyar/uLnqk1m5/1/#

I'm not seeing any exception, just a rejected Promise. The fact that you choose to console.error the rejection reason doesn't mean that a "regular" exception was thrown from the PDF.js code.
Looking at your example (focusing on the interesting bits):

...
loadingTask.promise.then(function(pdf) {
  ...
}, function (reason) { <-- This attaches a rejection handler, hence that will stop any further error propagation.
  // PDF loading error
  console.error(reason);
}).catch((e) => console.log('It is not catching here'));

loadingTask.destroy();

The easiest way to handle this would be to simplify your code like so:

...
loadingTask.promise.then(function(pdf) {
  ...
}).catch((e) => console.log('Here's the error you're expecting.'));

loadingTask.destroy();

or possibly:

...
loadingTask.promise.then(function(pdf) {
  ...
}, function (reason) {
  // PDF loading error
  console.error(reason);
  throw reason;
}).catch((e) => console.log('Here's the error you're expecting.''));

loadingTask.destroy();

All-in-all, there doesn't seem to be anything wrong with the PDF.js library here.
(If you're new to Promises, you may find a guide such as e.g. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises helpful.)

@doup
Copy link

doup commented Mar 4, 2021

I'm having the same issue, and no matter how I try to handle the promise (second then argument, catch, await/try) it stills bubbles up. From what I understand it's NOT the promise which is failing, it's the worker. So there is nothing to handle on the promise. Looks like the worker can't handle half-loaded documents (e.g. start loading a big PDF => call loadingTask.destroy() => get Worker was destroyed error).

If you search for the error in Google ("Worker was terminated" pdf.js) various users/libraries are having the same issue.

@Cyberhan123
Copy link

Cyberhan123 commented Jul 16, 2021

我遇到了同样的问题,无论我如何尝试处理承诺(第二个then参数,catch, await/try),它仍然会冒泡。据我所知,失败的不是承诺,而是工人。所以没有什么可以处理的承诺。看起来工作人员无法处理加载一半的文档(例如开始加载大 PDF => 调用loadingTask.destroy()=> 获取Worker was destroyed错误)。

如果您在 Google ( "Worker was terminated" pdf.js) 中搜索错误,则各个用户/库都会遇到相同的问题。

I got same , u should make sure not call destroy method,If you call this, It's mean worker will terminate, lifecycle will turn to unmount, if you use webpack load woker. The worker just load once ,It's the error reason

@aeaton-overleaf
Copy link

There are two separate errors:

  • "Worker was destroyed" is thrown by pdf.js and can be caught as described above.
  • "Worker was terminated" is thrown by pdf.worker.js and can't be caught in the same way.

@pinggi
Copy link

pinggi commented Nov 3, 2021

@doup is right.

React example - loads pdf in a component on mount:

useEffect(() => {
  const loadingTask = getDocument(testPdf.url);
  return () => {
    loadingTask.destroy(); // <-- we expect that it cancels the pdf loading
  };
}, []);

When the component is destroyed, we expect that it cancels the pdf loading and doesn't log anything to the console.
In fact it does log the exception.

It seems the exception happens here:

function getPdfManager(data, evaluatorOptions, enableXfa) {
  function setupDoc(data) {
    function onFailure(ex) {
       ensureNotTerminated(); <-- the code is: if (terminated) { throw new Error("Worker was terminated"); }

DevTools log:
image

@pinggi
Copy link

pinggi commented Nov 3, 2021

Perhaps the problem has a simple resolution - add a check if it was already destroyed:

if (loadingTask.destroyed) {
  loadingTask.destroy();
}

:-)

@codeWriter6
Copy link

I am encounter the same error, any solution?

@mikemathewson
Copy link

mikemathewson commented Jul 19, 2023

This issue is that the "await this._transport?.destroy();" line in the destroy() function prevents the worker from getting destroyed immediately.

The workaround is to destroy the worker manually:

loadingTask._worker.destroy()
loadingTask.destroy()

You can add some checks in as well to ensure no errors occur:

if (loadingTask._worker && !loadingTask._worker.destroyed) {
  loadingTask._worker.destroy()
}
if (!loadingTask.destroyed) {
  loadingTask.destroy()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants