synckit
Advanced tools
Comparing version 0.2.0 to 0.3.0
@@ -45,5 +45,9 @@ import { execSync } from 'child_process'; | ||
const tmpdir = fs.realpathSync(tmpdir$1()); | ||
const useWorkerThreads = !["0", "false"].includes(process.env.SYNCKIT_WORKER_THREADS); | ||
const { SYNCKIT_WORKER_THREADS, SYNCKIT_BUFFER_SIZE, SYNCKIT_TIMEOUT } = process.env; | ||
const useWorkerThreads = !SYNCKIT_WORKER_THREADS || !["0", "false"].includes(SYNCKIT_WORKER_THREADS); | ||
const DEFAULT_BUFFER_SIZE = SYNCKIT_BUFFER_SIZE ? +SYNCKIT_BUFFER_SIZE : void 0; | ||
const DEFAULT_TIMEOUT = SYNCKIT_TIMEOUT ? +SYNCKIT_TIMEOUT : void 0; | ||
const DEFAULT_WORKER_BUFFER_SIZE = DEFAULT_BUFFER_SIZE || 1024; | ||
const syncFnCache = new Map(); | ||
function createSyncFn(workerPath, bufferSize) { | ||
function createSyncFn(workerPath, bufferSize, timeout = DEFAULT_TIMEOUT) { | ||
if (!path.isAbsolute(workerPath)) { | ||
@@ -56,11 +60,7 @@ throw new Error("`workerPath` must be absolute"); | ||
} | ||
let resolvedWorkerPath = workerPath; | ||
if (!resolvedWorkerPath.endsWith(".ts")) { | ||
resolvedWorkerPath = require.resolve(workerPath); | ||
} | ||
const syncFn = (useWorkerThreads ? startWorkerThread : startChildProcess)(resolvedWorkerPath, bufferSize); | ||
const syncFn = (useWorkerThreads ? startWorkerThread : startChildProcess)(workerPath, bufferSize, timeout); | ||
syncFnCache.set(workerPath, syncFn); | ||
return syncFn; | ||
} | ||
function startChildProcess(workerPath) { | ||
function startChildProcess(workerPath, bufferSize = DEFAULT_BUFFER_SIZE, timeout) { | ||
const executor = workerPath.endsWith(".ts") ? "ts-node" : "node"; | ||
@@ -73,7 +73,9 @@ return (...args) => { | ||
execSync(command, { | ||
stdio: "inherit" | ||
stdio: "inherit", | ||
maxBuffer: bufferSize, | ||
timeout | ||
}); | ||
const { result, error } = JSON.parse(fs.readFileSync(filename, "utf8")); | ||
if (error) { | ||
throw typeof error === "object" && error && "message" in error ? Object.assign(new Error(), error) : error; | ||
throw typeof error === "object" && "message" in error ? Object.assign(new Error(), error) : error; | ||
} | ||
@@ -86,3 +88,3 @@ return result; | ||
} | ||
function startWorkerThread(workerPath, bufferSize = 1024) { | ||
function startWorkerThread(workerPath, bufferSize = DEFAULT_WORKER_BUFFER_SIZE, timeout) { | ||
const { port1: mainPort, port2: workerPort } = new MessageChannel(); | ||
@@ -103,4 +105,4 @@ const isTs = workerPath.endsWith(".ts"); | ||
worker.postMessage(msg); | ||
const status = Atomics.wait(sharedBufferView, 0, 0); | ||
if (status !== "ok" && status !== "not-equal") { | ||
const status = Atomics.wait(sharedBufferView, 0, 0, timeout); | ||
if (!["ok", "not-equal"].includes(status)) { | ||
throw new Error("Internal error: Atomics.wait() failed: " + status); | ||
@@ -118,3 +120,3 @@ } | ||
if (error) { | ||
throw Object.assign(error, properties); | ||
throw typeof error === "object" ? Object.assign(error, properties) : error; | ||
} | ||
@@ -160,2 +162,2 @@ return result; | ||
export { createSyncFn, runAsWorker, tmpdir, useWorkerThreads }; | ||
export { DEFAULT_BUFFER_SIZE, DEFAULT_TIMEOUT, DEFAULT_WORKER_BUFFER_SIZE, createSyncFn, runAsWorker, tmpdir, useWorkerThreads }; |
@@ -8,3 +8,6 @@ import { AnyAsyncFn, Syncify } from './types'; | ||
export declare const useWorkerThreads: boolean; | ||
export declare function createSyncFn<T extends AnyAsyncFn>(workerPath: string, bufferSize?: number): Syncify<T>; | ||
export declare const DEFAULT_BUFFER_SIZE: number | undefined; | ||
export declare const DEFAULT_TIMEOUT: number | undefined; | ||
export declare const DEFAULT_WORKER_BUFFER_SIZE: number; | ||
export declare function createSyncFn<T extends AnyAsyncFn>(workerPath: string, bufferSize?: number, timeout?: number): Syncify<T>; | ||
export declare const runAsWorker: <T extends AnyAsyncFn>(fn: T) => Promise<void>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.runAsWorker = exports.createSyncFn = exports.useWorkerThreads = exports.tmpdir = void 0; | ||
exports.runAsWorker = exports.createSyncFn = exports.DEFAULT_WORKER_BUFFER_SIZE = exports.DEFAULT_TIMEOUT = exports.DEFAULT_BUFFER_SIZE = exports.useWorkerThreads = exports.tmpdir = void 0; | ||
const tslib_1 = require("tslib"); | ||
@@ -16,5 +16,11 @@ const child_process_1 = require("child_process"); | ||
exports.tmpdir = fs_1.default.realpathSync(os_1.tmpdir()); | ||
exports.useWorkerThreads = !['0', 'false'].includes(process.env.SYNCKIT_WORKER_THREADS); | ||
const { SYNCKIT_WORKER_THREADS, SYNCKIT_BUFFER_SIZE, SYNCKIT_TIMEOUT } = process.env; | ||
exports.useWorkerThreads = !SYNCKIT_WORKER_THREADS || !['0', 'false'].includes(SYNCKIT_WORKER_THREADS); | ||
exports.DEFAULT_BUFFER_SIZE = SYNCKIT_BUFFER_SIZE | ||
? +SYNCKIT_BUFFER_SIZE | ||
: undefined; | ||
exports.DEFAULT_TIMEOUT = SYNCKIT_TIMEOUT ? +SYNCKIT_TIMEOUT : undefined; | ||
exports.DEFAULT_WORKER_BUFFER_SIZE = exports.DEFAULT_BUFFER_SIZE || 1024; | ||
const syncFnCache = new Map(); | ||
function createSyncFn(workerPath, bufferSize) { | ||
function createSyncFn(workerPath, bufferSize, timeout = exports.DEFAULT_TIMEOUT) { | ||
if (!path_1.default.isAbsolute(workerPath)) { | ||
@@ -27,7 +33,3 @@ throw new Error('`workerPath` must be absolute'); | ||
} | ||
let resolvedWorkerPath = workerPath; | ||
if (!resolvedWorkerPath.endsWith('.ts')) { | ||
resolvedWorkerPath = require.resolve(workerPath); | ||
} | ||
const syncFn = (exports.useWorkerThreads ? startWorkerThread : startChildProcess)(resolvedWorkerPath, bufferSize); | ||
const syncFn = (exports.useWorkerThreads ? startWorkerThread : startChildProcess)(workerPath, bufferSize, timeout); | ||
syncFnCache.set(workerPath, syncFn); | ||
@@ -37,3 +39,3 @@ return syncFn; | ||
exports.createSyncFn = createSyncFn; | ||
function startChildProcess(workerPath) { | ||
function startChildProcess(workerPath, bufferSize = exports.DEFAULT_BUFFER_SIZE, timeout) { | ||
const executor = workerPath.endsWith('.ts') ? 'ts-node' : 'node'; | ||
@@ -47,6 +49,8 @@ return (...args) => { | ||
stdio: 'inherit', | ||
maxBuffer: bufferSize, | ||
timeout, | ||
}); | ||
const { result, error } = JSON.parse(fs_1.default.readFileSync(filename, 'utf8')); | ||
if (error) { | ||
throw typeof error === 'object' && error && 'message' in error | ||
throw typeof error === 'object' && 'message' in error | ||
? // eslint-disable-next-line unicorn/error-message | ||
@@ -63,3 +67,3 @@ Object.assign(new Error(), error) | ||
} | ||
function startWorkerThread(workerPath, bufferSize = 1024) { | ||
function startWorkerThread(workerPath, bufferSize = exports.DEFAULT_WORKER_BUFFER_SIZE, timeout) { | ||
const { port1: mainPort, port2: workerPort } = new worker_threads_1.MessageChannel(); | ||
@@ -82,5 +86,5 @@ const isTs = workerPath.endsWith('.ts'); | ||
worker.postMessage(msg); | ||
const status = Atomics.wait(sharedBufferView, 0, 0); | ||
const status = Atomics.wait(sharedBufferView, 0, 0, timeout); | ||
/* istanbul ignore if */ | ||
if (status !== 'ok' && status !== 'not-equal') { | ||
if (!['ok', 'not-equal'].includes(status)) { | ||
throw new Error('Internal error: Atomics.wait() failed: ' + status); | ||
@@ -97,3 +101,3 @@ } | ||
// property copying manually. | ||
throw Object.assign(error, properties); | ||
throw typeof error === 'object' ? Object.assign(error, properties) : error; | ||
} | ||
@@ -100,0 +104,0 @@ return result; |
{ | ||
"name": "synckit", | ||
"version": "0.2.0", | ||
"description": "Perform async work synchronously in Node.js using a separate process with first-class TypeScript support", | ||
"version": "0.3.0", | ||
"description": "Perform async work synchronously in Node.js using `worker_threads`, or `child_process` as fallback, with first-class TypeScript support.", | ||
"repository": "git+https://github.com/rx-ts/synckit.git", | ||
@@ -6,0 +6,0 @@ "author": "JounQin <admin@1stg.me>", |
@@ -19,3 +19,3 @@ # synckit | ||
Perform async work synchronously in Node.js using a separate process with first-class TypeScript support | ||
Perform async work synchronously in Node.js using `worker_threads`, or `child_process` as fallback, with first-class TypeScript support. | ||
@@ -27,3 +27,5 @@ ## TOC <!-- omit in toc --> | ||
- [API](#api) | ||
- [Env variables](#env-variables) | ||
- [TypeScript](#typescript) | ||
- [Benchmark](#benchmark) | ||
- [Changelog](#changelog) | ||
@@ -74,2 +76,8 @@ - [License](#license) | ||
### Env variables | ||
1. `SYNCKIT_WORKER_THREADS`: whether or not enable `worker_threads`, it's enabled by default, set as `0` to disable | ||
2. `SYNCKIT_BUFFER_SIZE`: `bufferSize` to create `SharedArrayBuffer` for `worker_threads` (default as `1024`), or `maxBuffer` for `child_process` (no default) | ||
3. `SYNCKIT_TIMEOUT`: `timeout` for performing the async job (no default) | ||
### TypeScript | ||
@@ -83,2 +91,12 @@ | ||
## Benchmark | ||
It is about 20x faster than [`sync-threads`](https://github.com/lambci/sync-threads) but 3x slower than native for reading the file content itself 1000 times during runtime, and 18x faster than `sync-threads` but 4x slower than native for total time. | ||
And it's almost same as [`deasync`](https://github.com/abbr/deasync) but requires no native bindings or `node-gyp`. | ||
See [benchmark](./benchmarks/benchmark.txt) for more details. | ||
You can try it with running `yarn benchmark` by yourself. [Here](./benchmarks/benchmark.js) is the benchmark source code. | ||
## Changelog | ||
@@ -85,0 +103,0 @@ |
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
25145
334
109
5
3