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

Doesn't work with worker_threads #2263

Closed
Ugzuzg opened this issue Jun 17, 2020 · 6 comments
Closed

Doesn't work with worker_threads #2263

Ugzuzg opened this issue Jun 17, 2020 · 6 comments
Labels

Comments

@Ugzuzg
Copy link

Ugzuzg commented Jun 17, 2020

When running with worker threads, terminating a previous thread and trying to require('sharp') in a new worker thread again I'm getting the following output:

(sharp:47348): GLib-GObject-WARNING **: 13:22:02.604: cannot register existing type 'VipsObject'

(sharp:47348): GLib-CRITICAL **: 13:22:02.605: g_once_init_leave: assertion 'result != 0' failed

(sharp:47348): GLib-GObject-CRITICAL **: 13:22:02.605: g_type_register_static: assertion 'parent_type > 0' failed

(sharp:47348): GLib-CRITICAL **: 13:22:02.605: g_once_init_leave: assertion 'result != 0' failed

Are you using the latest version? Is the version currently in use as reported by npm ls sharp the same as the latest version as reported by npm view sharp dist-tags.latest?
Yes

What are the steps to reproduce?
https://github.com/Ugzuzg/sharp-worker-threads
Run node index.js

What is the expected behaviour?
sharp works with worker_threads.

Are you able to provide a minimal, standalone code sample, without other dependencies, that demonstrates this problem?
https://github.com/Ugzuzg/sharp-worker-threads
It has a dependency on threads which uses worker_threads internally.

Are you able to provide a sample image that helps explain the problem?
No image required.

What is the output of running npx envinfo --binaries --system?

  System:
    OS: Linux 5.7 Arch Linux
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    Memory: 2.43 GB / 15.28 GB
    Container: Yes
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 14.3.0 - /tmp/fnm-shell-4410774/bin/node
    Yarn: 1.22.4 - /usr/bin/yarn
    npm: 6.14.5 - /tmp/fnm-shell-4410774/bin/npm
@Ugzuzg Ugzuzg added the triage label Jun 17, 2020
@lovell
Copy link
Owner

lovell commented Jun 17, 2020

Hi, you'll need to ensure you require('sharp') in the main thread as well as worker threads.

Shared libraries are opened via dlopen and closed via dlclose on a reference counting basis. The use of terminate on a thread can result in dlclose being called on sharp, libvips and all of its dependencies. However the glib dependency does not respond to dlclose, so when dlopen is called a second time for sharp, libvips and all of its dependencies, they try to initialise themselves but it will fall over.

By requiring sharp in your main thread, you ensure the reference counter for all of its dependencies will always be at least 1, ensuring dlclose is only called after all work is complete.

@lovell lovell added question and removed triage labels Jun 17, 2020
@lovell
Copy link
Owner

lovell commented Jun 17, 2020

You can watch shared libraries opening "init" and closing "fini" as a program runs using:

LD_DEBUG=files G_DEBUG=fatal-warnings node index.js 2>&1 | egrep "calling (init|fini)"

@Ugzuzg
Copy link
Author

Ugzuzg commented Jun 17, 2020

Thanks, requiring sharp in the main thread does delay the closing to the end of execution, as you say. Any benefit of adding this information to the documentation?

I noticed that there is no such problem on Alpine Linux (using musl libc).

@lovell
Copy link
Owner

lovell commented Jun 18, 2020

Docs updated via commit c91373f, thanks for the suggestion.

The dlclose function is a "no-op" in musl libc, which is rather sensible, hence Alpine won't exhibit this behaviour.

https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading_libraries

@ericman314
Copy link

This suggestion is working for me too, unless the worker is terminated while converting an svg to a png and saving the png:

await sharp(Buffer.from(svgString))
  .toFile(fnPng)

If the main thread terminates the worker while the worker is executing the line above, then the entire main thread crashes with this:

terminate called after throwing an instance of 'Napi::Error'
  what():  
Aborted (core dumped)

I'm hoping you might recognize this error and know what I'm doing wrong. If you need me to provide code to reproduce this, or open a new issue, I would be happy to do that.

@lovell
Copy link
Owner

lovell commented Nov 9, 2020

@ericman314 You should not terminate in-flight worker threads where native modules are involved. See nodejs/node#34567 for more context, which includes the recent addition of experimental (N-)APIs to Node.js that we won't be able to use until at least Node.js 10 reaches EOL, possibly later.

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

No branches or pull requests

3 participants