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

Worker Threads: "Module did not self-register" #10

Closed
mattolson opened this issue Oct 10, 2018 · 11 comments
Closed

Worker Threads: "Module did not self-register" #10

mattolson opened this issue Oct 10, 2018 · 11 comments
Labels

Comments

@mattolson
Copy link
Contributor

When using the new experimental worker threads in Node 10.5 and above, if you require lzo in the worker, the following error is thrown:

Error: Module did not self-register.
    at Object.Module._extensions..node (internal/modules/cjs/loader.js:718:18)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at bindings (/Users/matt.olson/workspace/storefront-renderer/node_modules/bindings/bindings.js:76:44)
    at Object.<anonymous> (/Users/matt.olson/workspace/storefront-renderer/node_modules/lzo/index.js:3:36)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)

This seems to be related to nodejs/node#21783 and nodejs/node#21481. From the comments, it appears that this is a special case that authors of native addons need to handle. I'm really keen on getting this to work. Let me know if it's already on your radar or if you'd like some help with it. Thanks!

@schroffl
Copy link
Owner

schroffl commented Oct 11, 2018

I just tested it with Version 10.12.0 and a fresh copy of this repository:

abc.js

const { Worker } = require('worker_threads');
const worker = new Worker('./worker.js', { workerData: 'yo' });

worker.on('message', console.log);
worker.on('error', console.error);
worker.on('exit', code => console.log('Worker exit: ', code));

worker.js

const { workerData, parentPort } = require('worker_threads');
const lzo = require('.');

parentPort.postMessage(lzo.compress(workerData));

Result

$ node --version
v10.12.0

$ node --experimental-worker abc.js
Uint8Array [ 19, 121, 111, 17, 0, 0 ]
Worker exit:  0

@schroffl
Copy link
Owner

However, I found this Stackoverflow answer and in my bindings.gyp the files actually happen to be in the wrong order.
I can try to flip them around and publish a new version if you want to give it a shot :)

@mattolson
Copy link
Contributor Author

I’d be happy to test a new version. Glad to see there is nothing fundamentally wrong.

@schroffl
Copy link
Owner

I will aim to do that later today.

@schroffl
Copy link
Owner

I just published a new version. For some reason it's not yet visible on the npm website, but I can see it in the registry json.
Version 0.4.7 should be installed when you update.

@mattolson
Copy link
Contributor Author

I have been able to get a simple test case working with 0.4.7 that uses lzo in a worker thread. However, there's some other complexity in my app that is still leading to the same result. I'll let you know when I track it down. Thanks for the help.

@mattolson
Copy link
Contributor Author

mattolson commented Oct 20, 2018

Ok, it turns out that this issue happens when I require the lzo module in both the parent and the worker.

Here is my test code:

parent.js:

'use strict';

const util = require('util');
const { Worker } = require('worker_threads');

function sendMessage(worker, operation, input) {
    return new Promise((resolve, reject) => {
        // Process response message
        worker.on('message', response => {
            console.log(`Parent: received ${util.inspect(response)}`);

            if (response.errorMessage) {
                return reject(new Error(response.errorMessage));
            }

            return resolve(response.result);
        });

        // Send message to worker
        const message = {
            operation,
            input,
        };

        console.log(`Parent: sending ${util.inspect(message)}`);
        worker.postMessage(message);
    });
}

//const lzo = require('lzo'); // uncommenting this line causes the issue
const worker = new Worker('./child.js');

const input = 'foobar';
sendMessage(worker, 'compress', input).then(compressed => {
    console.log(`Parent: got compressed result from worker: ${compressed}`);
    sendMessage(worker, 'decompress', compressed).then(decompressed => {
        console.log(`Parent: got decompressed result from worker: ${Buffer.from(decompressed).toString()}`);
        process.exit();
    });
}).catch(err => {
    console.error(`Parent: got error from worker: ${result}`);
    process.exit(1);
});

child.js:

'use strict';

const lzo = require('lzo');
const util = require('util');
const { parentPort, workerData } = require('worker_threads');

function compress(message) {
    return lzo.compress(message);
}

function decompress(message) {
    return lzo.decompress(message, message.length * 10);
}

function sendResponse(operation, result) {
    const response = {
        operation,
        result,
    };
    console.log(`Child: sending ${util.inspect(response)}`);
    parentPort.postMessage(response);
}

function sendError(operation, err) {
    const response = {
        operation,
        errorMessage: err.message, // can't serialize Errors
    };
    console.log(`Child: sending ${util.inspect(response)}`);
    parentPort.postMessage(response);
}

parentPort.on('message', message => {
    console.log(`Child: received ${util.inspect(message)}`);

    let result;
    switch(message.operation) {
        case 'compress':
            result = compress(message.input);
            sendResponse(message.operation, result);
            break;
        case 'decompress':
            result = decompress(message.input);
            sendResponse(message.operation, result);
            break;
        case 'terminate':
            process.exit(0);
            break;
    }
});

Uncommenting the require of lzo in parent.js causes the error, which occurs in the worker thread during the second require.

Error: Module did not self-register.
    at Object.Module._extensions..node (internal/modules/cjs/loader.js:718:18)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at bindings (/Users/matt.olson/workspace/storefront-renderer/node_modules/bindings/bindings.js:76:44)
    at Object.<anonymous> (/Users/matt.olson/workspace/storefront-renderer/node_modules/lzo/index.js:3:36)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)

@mattolson
Copy link
Contributor Author

I don't know if this applies to you, but this might help? nodejs/node#21783 (comment)

@schroffl
Copy link
Owner

That definitely looks like it might help, I will check it out and try to publish a new release next week. Thanks for your research so far :)

@schroffl
Copy link
Owner

This is published in Version v0.4.8

@mattolson
Copy link
Contributor Author

Thank you!

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

2 participants