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

Usage with Worker Threads #237

Closed
clemlesne opened this issue Feb 28, 2019 · 40 comments
Closed

Usage with Worker Threads #237

clemlesne opened this issue Feb 28, 2019 · 40 comments

Comments

@clemlesne
Copy link

clemlesne commented Feb 28, 2019

Hello,

I use a node.js app in order to benchmark an application server. I use for that a queue combined with multiple threads managed by Node Worker Threads.

better-sqlite3 is excellent for parallel access, so I wanted to use it in my app. The problem is when I include the module in my worker, an error Module did not self-register. appear.

Environments

better-sqlite: v5.4.0

Tested with node:

  • 11.10.0
  • 10.15.1
  • 10.15.0

System: Windows 10 1709

Steps to reproduce

  1. Write a new node module with the worker threads integration
const {
  Worker, isMainThread, parentPort, workerData
} = require('worker_threads');

if (isMainThread) {
  module.exports = function parseJSAsync(script) {
    return new Promise((resolve, reject) => {
      const worker = new Worker(__filename, {
        workerData: script
      });
      worker.on('message', resolve);
      worker.on('error', reject);
      worker.on('exit', (code) => {
        if (code !== 0)
          reject(new Error(`Worker stopped with exit code ${code}`));
      });
    });
  };
} else {
  const { parse } = require('some-js-parsing-library');
  const script = workerData;
  parentPort.postMessage(parse(script));
}
  1. Include better-sqlite3 module
const sqlite = require('better-sqlite3'); // the new added module
const {
  Worker, isMainThread, parentPort, workerData
} = require('worker_threads');

if (isMainThread) {
...
  1. See the error
Error: Module did not self-register.
    at Object.Module._extensions.node (internal/modules/cjs/loader.js:779:18)
    at Module.load (internal/modules/cjs/loader.js:630:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:570:12)
    at Function.Module._load (internal/modules/cjs/loader.js:562:3)
    at Module.require (internal/modules/cjs/loader.js:667:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> ([XXX]\node_modules\\better-sqlite3\\lib\\database.js:5:21)
    at Module._compile (internal/modules/cjs/loader.js:738:30)
    at Object.Module._extensions.js (internal/modules/cjs/loader.js:749:10)
    at Module.load (internal/modules/cjs/loader.js:630:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:570:12)
    at Function.Module._load (internal/modules/cjs/loader.js:562:3)
    at Module.require (internal/modules/cjs/loader.js:667:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.<anonymous> ([XXX]\node_modules\\better-sqlite3\\lib\\index.js:2:18)
    at Module._compile (internal/modules/cjs/loader.js:738:30)

Related sources

I have already trace some related articles:

Regards,

@JoshuaWise
Copy link
Member

The ability to use native addons within worker threads is very new (Node 11.11.0 and up). Node.js also requires the addon (better-sqlite3, in this case) to be cooperative, which means no existing addons will automatically have this ability. It's possible to support this, but it will require significant updates to better-sqlite3. I'll mark this as "enhancement", and perhaps support for it can be added some day in the future.

@wmertens
Copy link

Hijacking this to muse about how it would work with threads.

I really want to use this library, but I would have to run it in a different process to have a responsive webserver at all times, and worker threads look like a nice middle ground, even giving parallelization for read-only workloads.

Unfortunately, the communication with the worker needs to undergo a serialization/deserialization step. The most performant way to communicate with worker threads seems to be a SharedArrayBuffer.

I wonder what would be a nice way to serialize sqlite responses directly without having to go through the Node abstractions, and then do the deserialization in the main thread from the SharedArrayBuffer.

@micooz
Copy link

micooz commented Mar 8, 2020

I encountered this problem too, here is cleaner code to reproduce:

const { Worker, isMainThread } = require('worker_threads');

if (isMainThread) {
  require('better-sqlite3');
  new Worker(__filename);
} else {
  require('better-sqlite3'); // Error: Module did not self-register
}

@JoshuaWise
Copy link
Member

This is now supported in v7.0.0. See an example here.

@m4heshd
Copy link
Contributor

m4heshd commented Feb 18, 2021

Hi @JoshuaWise. Thank you for the awesome library and giving this solution. But the polling process is eating my CPU up when using your solution. One core is pretty much being dedicated to it. Even in idle since It's constantly poking the queue. Any alternative? I'm looking for a solution to be used directly in electron renderer which doesn't support worker threads. Web worker is a mess too. I need to support very frequent queries done through user input without blocking the UI even for a few milliseconds.

@wmertens
Copy link

@m4heshd from what I can find, worker_threads should work in electron in the main process: electron/electron#18540 (comment)

What do you mean with queue polling?

@m4heshd
Copy link
Contributor

m4heshd commented Feb 19, 2021

Hi @wmertens. Thanks for the input. It does work with the main process but unfortunately electron seems not stable enough to handle that. The process always ends up with an access violation error (code 3221225477) even though the workers are terminated and properly cleaned up. It does seem to work on some versions but I can't have my code dependent to old specific versions of Electron. That's just some big technical debt. It also is such a pain to do IPC for all that because 99% of my DB requirements come from the renderer (So child processes are a pain too). It's a shame that I wasted my whole night writing some good code which I had to throw away because of this.

What do you mean with queue polling?

It constantly checks the queue for new tasks which takes a toll on the CPU. You can clearly see It if you take a closer look at all the cores. One core is being utilized 100% for this task. Might create different results on different libuv versions and CPUs. Although I thought of a solution while writing this but still doesn't matter since Electron plays angry with it.

It was so much effort get webpack to properly bundle workers but Electron web worker doesn't like to load external node modules even though the documentation clearly says so. One disappointment followed by another. It's an endless journey of jumping through hoops.

I love Electron with all my heart and better-sqlite3 is the sweet cherry on top. Done some really impressive projects in the past with Electron. But the amount of time wasted on these tiny little unstable stuff is infuriating coming from other statically written more stable languages and all the accompanied technologies.

(Really really sorry about the rant in advance. Just have to pour out my frustration somewhere.)

@wmertens
Copy link

wmertens commented Feb 19, 2021

@m4heshd Hmm, that sucks. From my perspective, I would

  • report the worker_thread crashes and hope they get resolved (since it works in some versions). Getting better-sqlite to work in a Web Worker seems a risky endeavour.
  • open a new issue here to address the polling. Doesn't seem right that it has to poll?

Too bad about your code, but take solace from the fact that we've all been there :)

@m4heshd
Copy link
Contributor

m4heshd commented Feb 19, 2021

Too bad about your code, but take solace from the fact that we've all been there :)

@wmertens haha thank you for relating. I'll definitely get to those tasks.

Getting better-sqlite to work in a Web Worker seems a risky endeavour.

You couldn't be more right. Even their documentation says that. Mostly upon evidence of how unstable these modules are, I should be stupid to go down this road of ✨ threads in Electron ✨. And really glad you said it because I've come to a conclusion now. This whole day I was thinking, screw this sync async bull. I've always appreciated synchronous code. It's much faster, easy to control and super reliable. I'll let the GUI hang for a few milliseconds. So what. My clients would appreciate data stability over some crisp smooth GUI like it always has been for them (with Java + threads). It's not a competitive FPS game to have that much sharp responsiveness 🤣. People are going super overboard with this async stuff (It's a good thing but not always).

Meanwhile, do let me know if you stumble upon any alternatives to overcome this.

@wmertens
Copy link

Do note that:

  • I'm not @JoshuaWise ;)
  • I do think the polling is a problem if it's caused by better-sqlite and it deserves a new issue
  • I do think sync access make sense for sqlite
  • I don't like hanging GUI apps for potentially seconds
  • I did mean Web Workers were a problem, not worker_threads.

Not sure how your app is structured, but IMHO the bridging from main to render shouldn't be a big issue? Especially if you have an abstraction layer around the DB that converts chatty SQL to compact internal representation before bridging?

It does sound like Electron worker threads aren't ready for it though, I'd really chase down those problems too...

But of course, it's always a matter of picking your battles.

@JoshuaWise
Copy link
Member

It constantly checks the queue for new tasks which takes a toll on the CPU. You can clearly see It if you take a closer look at all the cores. One core is being utilized 100% for this task.

If you're hitting 100% CPU usage and you're referring to the polling that's being used in this example, then there is almost certainly something wrong with your runtime's implementation of setImmediate(). Try something like setTimeout(poll, 1) instead.

As for the using better-sqlite3 in Web Workers, perhaps it's possible, but your mileage may vary, and it's not something I officially support because better-sqlite3 is a Node.js module and not a WebKit module (which is why all Electron support is provided by the community, and not me personally).

@wmertens
Copy link

@JoshuaWise so in the example, the queue polling could be replaced by immediately assigning a worker on receiving the query, no? I don't understand what the queue is for.

@JoshuaWise
Copy link
Member

JoshuaWise commented Feb 19, 2021

Each worker thread can only execute one query at a time. If all of the workers are busy, you need to put the query into a queue. By having a shared queue, you ensure that the work is distributed evenly among the workers.

You could, instead, give each worker its own private queue, and rotate between them as new work comes in. However, the problem with that approach is that some queries could take much longer than others, which means you could get unlucky and a single worker could get overloaded with large queries while the other workers wait around doing nothing. Using a shared queue prevents this from ever happening.

If you simply send new messages to the workers without using any queues, it's equivalent to using a private queue for each worker, because each worker has a built-in private queue for receiving messages.

@m4heshd
Copy link
Contributor

m4heshd commented Feb 19, 2021

I did mean Web Workers were a problem, not worker_threads.

@wmertens I know. I didn't misunderstand it. I tested pretty much everything for hours but all useless since Electron can't play nice with any good approach. So sad.

@JoshuaWise Yes I was referring to the example since the first post. I know, everything's good. better-sqlite3 is perfect. Also works perfectly with worker threads. I'm using my own version which I named better-sqleet compiled with sqleet amalgamation. I also included a prebuilt better-sqleet-v7.1.2-electron-v85-win32-x64.tar.gz there so my project will have maximum compatibility with it. It's lightning fast, encrypted and all good.

Only issue is that Electron failing to support any of this. While I was asking for an alternative on the first comment, I haven't gotten to the Electron issues yet other than the polling problem. So no complains from me about better-sqlite3.

Each worker thread can only execute one query at a time. If all of the workers are busy, you need to put the query into a queue. By having a shared queue, you ensure that the work is distributed evenly among the workers.

You posted this while I was writing the same explanation 😁 although I mentioned about the storing and calling of each promise. That was a really good approach. I actually have a solution to the polling issue. Lemme try it quickly.

Electron support is provided by the community, and not me personally

You don't have to. It's pretty straight forward. Thank you for everything that you've already done. More than enough.

@m4heshd
Copy link
Contributor

m4heshd commented Feb 19, 2021

Ok @JoshuaWise here you go. I had this halfway done yesterday but gave up because of the Electron incompatibility. Works for me perfectly. Do test and let me know. I'll create a PR for this right away. Here's the CPU usage.

Before:

before

After:

after

Code:

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

/*
  Export a function that queues pending work.
 */

const queue = [];
exports.asyncQuery = (sql, ...parameters) => {
    return new Promise((resolve, reject) => {
        queue.push({
            resolve,
            reject,
            message: { sql, parameters },
        });
        callWorkers();
    });
};

/*
  Call poll() in every worker upon new asyncQuery request.
 */

let workers = [];
function callWorkers() {
    workers.forEach((worker) => {
        worker.poll();
    })
}

/*
  Spawn workers that try to drain the queue.
 */

os.cpus().forEach(function spawn() {
    const worker = new Worker('./worker.js');
    const threadId = worker.threadId;

    let job = null; // Current item from the queue
    let error = null; // Error that caused the worker to crash

    function poll() {
        if (!job && queue.length) {
            // If there's a job in the queue, send it to the worker
            job = queue.shift();
            worker.postMessage(job.message);
        }
    }

    worker
        .on('online', poll)
        .on('message', (result) => {
            job.resolve(result);
            job = null;
            poll(); // Check if there's more work to do
        })
        .on('error', (err) => {
            console.error(err);
            error = err;
        })
        .on('exit', (code) => {
            workers = workers.filter(w => w.threadId !== threadId);
            if (job) {
                job.reject(error || new Error('worker died'));
            }
            if (code !== 0) {
                console.error(`worker exited with code ${code}`);
                spawn(); // Worker died, so spawn a new one
            }
        });

    workers.push({threadId, poll});
});

The issue was setImmediate(poll) creating an infinite loop in the if condition which hogged the CPU. I knew that yesterday but was too lazy to fix it because it serves me no purpose. But this one's for the community.

@wmertens
Copy link

I would call the callWorkers function from the asyncQuery after queuing. I don't understand why the polling is needed. Don't the worker messages get queued?
And if they don't get queued, all it takes is calling poll right after job completion.

This way, either a worker is available at the moment of queuing a job, or they will check when they complete. No polling.

@m4heshd
Copy link
Contributor

m4heshd commented Feb 19, 2021

I would call the callWorkers function from the asyncQuery after queuing

@wmertens I already do that in the above example. You might've seen an earlier edit where i accidentally left out some stuff while merging my code with the example from repo.

I don't understand why the polling is needed

Because when all the workers comes to an idle state and the queue was empty at that time, they won't know when the new jobs arrive anymore because there won't be any events fired from worker's scope. Any type of queueing needs some kind of polling. This way it's much efficient and faster than constantly checking for updates in a loop.

This code needs some more adjustments for destroyed workers. I'm testing those updates right now. Will update the code soon.

UPDATE: Just updated it

@wmertens
Copy link

Ah yes, now it's good. With no polling I meant no setimmediate, and that is now gone. I expect this to eat no CPU at all?

@m4heshd
Copy link
Contributor

m4heshd commented Feb 20, 2021

Yes it is. As you can see from above stats, CPU is chilling with all four threads idling. Only if this worked with Electron properly. 😒

UPDATE: My issue has been fixed in Electron 12 since it's using Node v14 ABI. All good now.

@JonathanWoodward
Copy link

This is now supported in v7.0.0. See an example here.

I have tried this solution on the back end of an electron application and it works well whilst in debug mode however when I build the application into a release require('better-sqlite3') is only found if the better-sqlite3 node_modules is located within the project. Do you know how this could be built in and be used from the worker thread like it is in does in the main thread?

@m4heshd
Copy link
Contributor

m4heshd commented Jan 25, 2022

@JonathanWoodward You can't have your worker code packed into the build asar. I'm gonna take a guess here that you might be using electron-builder. It provides you an option called asarUnpack. Add the following option to your builder configuration.

{
    asarUnpack: [
        "**/node_modules/better-sqlite3/**/*",
        "**/node_modules/bindings/**/*",
        "**/node_modules/file-uri-to-path/**/*",
        // also include your worker files here....
    ]
}

Then you might run into another issue where Electron's own fs module (which knows how to automatically import packed and unpacked modules) can't find the worker files when packaged. It depends on how you implement your worker. If you run into this, make sure it knows the proper path to the worker when packaged. Something like this..

const workerScript = process.env.NODE_ENV === 'production' ?
    path.join(process.resourcesPath, 'app.asar.unpacked', 'my-worker.js') :
    path.join(__dirname, 'my-worker.js');

@JonathanWoodward
Copy link

Hi @m4heshd , thank you for your reply. Would this impose a security vulnerability where the packed source could be modified leading to some form of injection?

@m4heshd
Copy link
Contributor

m4heshd commented Jan 25, 2022

Would this impose a security vulnerability where the packed source could be modified leading to some form of injection?

It most definitely does. That's something very difficult to avoid when it comes to Electron even if the app is fully packaged into the asar. They can be very easily unpacked and repacked.

npm i -g asar
asar extract app.asar extracted

Best bet here for you would be either properly obfuscating your production code (fairly effortless) or using V8 snapshots (which can be very difficult).

@JonathanWoodward
Copy link

@m4heshd are there any known ways to obfuscation in Electron.js then checksum each of the files for tamper detection?

@m4heshd
Copy link
Contributor

m4heshd commented Jan 25, 2022

@JonathanWoodward My recommendation is javascript-obfuscator. You can give it a quick test here.

@JoshuaWise
Copy link
Member

I have tried this solution on the back end of an electron application and it works well whilst in debug mode however when I build the application into a release require('better-sqlite3') is only found if the better-sqlite3 node_modules is located within the project. Do you know how this could be built in and be used from the worker thread like it is in does in the main thread?

If this is an issue of bindings not being resolved, you can solve it by using the new nativeBinding option in version 7.5.0.

@JonathanWoodward
Copy link

@JonathanWoodward You can't have your worker code packed into the build asar. I'm gonna take a guess here that you might be using electron-builder. It provides you an option called asarUnpack. Add the following option to your builder configuration.

{
    asarUnpack: [
        "**/node_modules/better-sqlite3/**/*",
        "**/node_modules/bindings/**/*",
        "**/node_modules/file-uri-to-path/**/*",
        // also include your worker files here....
    ]
}

Then you might run into another issue where Electron's own fs module (which knows how to automatically import packed and unpacked modules) can't find the worker files when packaged. It depends on how you implement your worker. If you run into this, make sure it knows the proper path to the worker when packaged. Something like this..

const workerScript = process.env.NODE_ENV === 'production' ?
    path.join(process.resourcesPath, 'app.asar.unpacked', 'my-worker.js') :
    path.join(__dirname, 'my-worker.js');

@m4heshd I may be missing your point with this but should this allow me in my-worker.js just require('better-sqlite3') normally or should I be using the workerScript path to the modules? I've tried a few things and had no success, it's probably my stupidity.

@m4heshd
Copy link
Contributor

m4heshd commented Jan 25, 2022

you can solve it by using the new nativeBinding option in version 7.5.0.

This is solid but you still would be required to check if the application's in production to point to the native binary since the location to that changes when packaged and Electron's patched fs somehow fails to pick up unpacked modules when worker_threads are involved.

@m4heshd
Copy link
Contributor

m4heshd commented Jan 25, 2022

should this allow me in my-worker.js just require('better-sqlite3') normally

Yes it would. For an example, this is the worker source file (unedited) of a project I'm currently shipping.

const {parentPort, workerData} = require('worker_threads');
const db = require('better-sqlite3-multiple-ciphers')(workerData.__dbPath, {
    fileMustExist: true,
    verbose: process.env.VUELECTRO_ENV === 'build' ? null : require(workerData.loggerPath).logDBVerbose
});

if (workerData.isDBEncrypted) db.pragma(`key='${workerData.key}'`);

parentPort.on('message', ({type, sql, parameters}) => {
    if (type === 'terminate') {
        db.close();
        process.exit();
    } else {
        let result = {
            error: null,
            data: null
        }

        try {
            result.data = db.prepare(sql).all(...parameters);
        } catch (error) {
            result.error = error.toString();
        }

        parentPort.postMessage(result);
    }
});

This works perfectly fine on all platforms, in all scenarios.

One thing I forgot to mention in the previous response, you cannot use the eval mode of worker_threads with external modules. It would lead to the exact issue you originally mentioned. But in that case, what @JoshuaWise suggested might work.

@JonathanWoodward
Copy link

@m4heshd is it possible to pkg better-sqlite into a worker in a node service separate from electron?

`
@GCN0185 MINGW64 /c/git/SquirrelViewData (master)
$ pkg index.js

pkg@5.5.2
Targets not specified. Assuming:
node16-linux-x64, node16-macos-x64, node16-win-x64

@GCN0185 MINGW64 /c/git/SquirrelViewData (master)
$ node index.js
PRAGMA journal_mode = WAL
Connection to local database has been established successfully.
Server ready at http://localhost:8454/ http://192.168.10.47:8454

@GCN0185 MINGW64 /c/git/SquirrelViewData (master)
$ ./index-win.exe
PRAGMA journal_mode = WAL
Connection to local database has been established successfully.
Server ready at http://localhost:8454/ http://192.168.10.47:8454
[worker eval]:1
[native code]
^^^^

SyntaxError: Unexpected identifier
at new Script (node:vm:101:7)
at createScript (node:vm:259:10)
at Object.runInThisContext (node:vm:307:10)
at node:internal/process/execution:75:19
at [worker eval]-wrapper:6:22
at evalScript (node:internal/process/execution:74:60)
at MessagePort. (node:internal/main/worker_thread:176:7)
at MessagePort.[nodejs.internal.kHybridDispatch] (node:internal/event_target:562:20)
at MessagePort.exports.emitMessage (node:internal/per_context/messageport:23:28)
worker exited with code 1
[worker eval]:1
[native code]
`

@m4heshd
Copy link
Contributor

m4heshd commented Jan 26, 2022

@JonathanWoodward I think you should share a minimal repro of what you're trying to achieve. That would help a lot on debugging this.

@JonathanWoodward
Copy link

m4heshd added a commit to m4heshd/pkg-worker-better-sqlite that referenced this issue Jan 27, 2022
@m4heshd
Copy link
Contributor

m4heshd commented Jan 27, 2022

@JonathanWoodward Check my PR on your repo.

I expected a repro of your Electron approach. I sense that you've given up on trying to fix the issue on Electron's side and trying this hacky method. But I highly suggest not to go this way. You're gonna lose a lot of control doing this and not to mention you might end up corrupting your DBs. What I recommend is to share an absolutely minimal repro of your Electron project and then I'll hopefully be able to assist you with debugging this in a much cleaner way.

@JonathanWoodward
Copy link

JonathanWoodward commented Jan 27, 2022

@m4heshd No, I have the electron approach working. I am trying to "compile" the code and produce a Windows ".exe" so the source code is not exposed. The package you produced pkg-worker-better-sqlite-1.0.0.tgz is not the same as index-win.exe.

@JonathanWoodward
Copy link

JonathanWoodward commented Jan 27, 2022

@m4heshd this is the compiled version with your changes.

/c/git/pkg-worker-better-sqlite (main) $ ./index-win.exe Error: Cannot find module 'C:\snapshot\pkg-worker-better-sqlite\worker.js' at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15) at Function._resolveFilename (pkg/prelude/bootstrap.js:1819:46) at Function.Module._load (node:internal/modules/cjs/loader:778:27) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) at MessagePort.<anonymous> (node:internal/main/worker_thread:187:24) at MessagePort.[nodejs.internal.kHybridDispatch] (node:internal/event_target:562:20) at MessagePort.exports.emitMessage (node:internal/per_context/messageport:23:28) { code: 'MODULE_NOT_FOUND', requireStack: [] }

@m4heshd
Copy link
Contributor

m4heshd commented Jan 27, 2022

@JonathanWoodward I'm pretty sure you didn't run the changes from that PR. If you did, it should output dist/pkg-worker-better-sqlite.exe. If you checked out the changes correctly, this should be the output of your packaged binary.

image

I even moved it completely away from the project directory.

@JonathanWoodward
Copy link

@JonathanWoodward I'm pretty sure you didn't run the changes from that PR. If you did, it should output dist/pkg-worker-better-sqlite.exe.

@m4heshd apologies I missed a line out.

What version of node are you using? I now get the following error which I can't seem to resolve:

/c/git/pkg-worker-better-sqlite/dist (main)
$ ./pkg-worker-better-sqlite.exe
timeout add MyWorkerTask
Error: The module 'C:\Users\JONATH~1.WOO\AppData\Local\Temp\pkg\9db95638e758025937af39ea4f982a1baff5f4c9b55d6bc605d4c06d94779902\better-sqlite3\build\Release\better_sqlite3.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 93. This version of Node.js requires
NODE_MODULE_VERSION 83. Please try re-compiling or re-installing
the module (for instance, using npm rebuild or npm install).
at process.dlopen (pkg/prelude/bootstrap.js:2114:28)
at Object.Module._extensions..node (internal/modules/cjs/loader.js:1144:18)
at Module.load (internal/modules/cjs/loader.js:950:32)
at Function.Module._load (internal/modules/cjs/loader.js:790:12)
at Module.require (internal/modules/cjs/loader.js:974:19)
at Module.require (pkg/prelude/bootstrap.js:1719:31)
at require (internal/modules/cjs/helpers.js:93:18)
at bindings (C:\snapshot\pkg-worker-better-sqlite\node_modules\bindings\bindings.js:112:48)
at new Database (C:\snapshot\pkg-worker-better-sqlite\node_modules\better-sqlite3\lib\database.js:48:64)
at Database (C:\snapshot\pkg-worker-better-sqlite\node_modules\better-sqlite3\lib\database.js:11:10) {
code: 'ERR_DLOPEN_FAILED'
}

@m4heshd
Copy link
Contributor

m4heshd commented Jan 27, 2022

What version of node are you using? I now get the following error which I can't seem to resolve:

I use Node 14. That's why I mentioned the following on your PR note.

I've set the target to node14-win-x64 but feel free to change it to your locally installed Node.js version before packaging.

Also if this conversation moves further, it should be moved to your repo's PR.

@JonathanWoodward
Copy link

Very nice, thanks for the help.

$ ./pkg-worker-better-sqlite.exe
timeout add MyWorkerTask
WORKER task completed task: TEST { changes: 0, lastInsertRowid: 0 }
timeout add MyWorkerTask
WORKER task completed task: TEST { changes: 0, lastInsertRowid: 0 }
timeout add MyWorkerTask
WORKER task completed task: TEST { changes: 0, lastInsertRowid: 0 }
timeout add MyWorkerTask
WORKER task completed task: TEST { changes: 0, lastInsertRowid: 0 }

@alexgleason
Copy link

This is now supported in v7.0.0. See an example here.

I think special handling of begin and commit queries may be needed. Otherwise begin could be called by one worker, the query itself run by another work, and commit run by yet another worker.

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

No branches or pull requests

7 participants