I'm using child_process to spawn a child process and get return PID from it. I need to manage this child process by its PID. Below is my code:
const childProcess = require('child_process');
let options = ['/c', arg1, arg2];
const myProcess = childProcess.spawn('cmd.exe', options, {
detached: false,
shell: false
});
let pid = myProcess.pid;
During run time, I want to use PID to validate independently from outside if the process is running or not (finished / killed). I want to know how to do this and what is the best way to make this validation in Nodejs?. I'm running application in Windows environment.
Any suggestion is appreciated, thanks.
I found out a solution as suggestion of is-running module. But I don't want to install new module into my project just for this purpose, so I created my own checkRunning() function as below:
// Return true if process following pid is running
checkRunning(pid) {
try {
return process.kill(pid, 0);
} catch (error) {
console.error(error);
return error.code === 'EPERM';
}
}
Following the Nodejs document about process.kill(pid[, signal]), I can use process.kill() to check the existence of process with specific signal argument is value 0 (not killing process as function name).
I make a copy of the document said:
As a special case, a signal of 0 can be used to test for the existence of a process
Probably this will help, npm module called is-running https://npmjs.org/package/is-running as was mentioned here -
https://stackoverflow.com/a/14884949/7927724
If you want to know when a child process exits, you can check the exit event
const { spawn } = require('child_process');
const bat = spawn('cmd.exe', ['/c', 'my.bat']);
bat.stdout.on('data', (data) => {
console.log(data.toString());
});
bat.stderr.on('data', (data) => {
console.log(data.toString());
});
bat.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
});
Here is a code fragment as a reference
win32 (cond) {
return new Promise((resolve, reject) => {
const cmd = 'WMIC path win32_process get Name,Processid,ParentProcessId,Commandline,ExecutablePath'
const lines = []
const proc = utils.spawn('cmd', ['/c', cmd], { detached: false, windowsHide: true })
proc.stdout.on('data', data => {
lines.push(data.toString())
})
proc.on('close', code => {
if (code !== 0) {
return reject(new Error('Command \'' + cmd + '\' terminated with code: ' + code))
}
let list = utils.parseTable(lines.join('\n'))
.filter(row => {
if ('pid' in cond) {
return row.ProcessId === String(cond.pid)
} else if (cond.name) {
if (cond.strict) {
return row.Name === cond.name || (row.Name.endsWith('.exe') && row.Name.slice(0, -4) === cond.name)
} else {
// fix #9
return matchName(row.CommandLine || row.Name, cond.name)
}
} else {
return true
}
})
.map(row => ({
pid: parseInt(row.ProcessId, 10),
ppid: parseInt(row.ParentProcessId, 10),
// uid: void 0,
// gid: void 0,
bin: row.ExecutablePath,
name: row.Name,
cmd: row.CommandLine
}))
resolve(list)
})
})
},
which come from https://github.com/yibn2008/find-process/blob/master/lib/find_process.js
For the related subject here the best packages
Check only by pid
https://www.npmjs.com/package/is-running
Search by pid, name patterns and different means packages:
https://www.npmjs.com/package/find-process
https://www.npmjs.com/package/ps-node
https://github.com/sindresorhus/process-exists
Related
I'm using node.js child_proccess.spawn() in order to execute few command lines in CMD and get the output.
I have encountered few issues:
When i'm trying to spawn the proccess witout stdio: 'inherit' option - The CMD freezes after executing the last command and won't print out the results.
When I add the stdio: 'inherit' option, I get the results printed to my terminal but I cant catch the output with child.stdout.on..
Is there any possible way to capture the terminal output or to avoid the proccess from being stuck?
function executeCommands (){
const firstCommand = 'do something1'
const secondCommand = 'do something2'
const thirdCommand = 'do something3'
let child = require('child_process').spawn(`${firstCommand} && ${secondCommand} &&
${thirdCommand}`, [], {shell: true,stdio: 'inherit'})
child.stdout.setEncoding('utf8')
child.stdout.on('data', (data) => {
console.log('stdout',data)
})
child.stdio.on('data', (data) => {
console.log('stdio',data)
})
child.stderr.on('data', (data) => {
console.log('stderr',data.toString())
})
}
Use child_process
const { execSync } = require("node:child_process");
const npmVersion = execSync("npm -v", { encoding: "utf-8" });
console.log(npmVersion);
// 8.15.0
if you want to use spawnSync
const { spawnSync } = require("node:child_process");
const npmVersion = spawnSync("npm", ["-v"], { encoding: "utf-8" });
console.log(npmVersion.stdout);
// 8.15.0
I have deployed a next-js app to plesk hosting and after a shed ton of tinkering managed to get it working. However it is returning 500 internal server errors in the console when requesting the static assets, see example below:
GET https://nextjs-test.reachtest.co.uk/_next/static/css/120f2e2270820d49a21f.css [HTTP/1.1 500 Internal Server Error 11ms]
As this is just for testing, it is quite simply just the initial npx create-next-app.
Link: https://nextjs-test.reachtest.co.uk/
In order to get the App even running I had to copy the start script from nextjs and point all of the requires back to node_modules and change the defaultCommand from:
next dev
to:
next start
See the file below:
#!/usr/bin/env node
"use strict"; var log = _interopRequireWildcard(require("./node_modules/next/dist/build/output/log.js")); var _index = _interopRequireDefault(require("./node_modules/next/dist/compiled/arg/index.js")); var _constants = require("./node_modules/next/dist/lib/constants"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } ['react', 'react-dom'].forEach(dependency => {
try {// When 'npm link' is used it checks the clone location. Not the project.
require.resolve(dependency);
} catch (err) { console.warn(`The module '${dependency}' was not found. Next.js requires that you include it in 'dependencies' of your 'package.json'. To add it, run 'npm install ${dependency}'`); }
}); const defaultCommand = 'start'; const commands = { build: () => Promise.resolve().then(() => _interopRequireWildcard(require('./node_modules/next/dist/cli/next-build'))).then(i => i.nextBuild), start: () => Promise.resolve().then(() => _interopRequireWildcard(require('./node_modules/next/dist/cli/next-start'))).then(i => i.nextStart), export: () => Promise.resolve().then(() => _interopRequireWildcard(require('./node_modules/next/dist/cli/next-export'))).then(i => i.nextExport), dev: () => Promise.resolve().then(() => _interopRequireWildcard(require('./node_modules/next/dist/cli/next-dev'))).then(i => i.nextDev), lint: () => Promise.resolve().then(() => _interopRequireWildcard(require('./node_modules/next/dist/cli/next-lint'))).then(i => i.nextLint), telemetry: () => Promise.resolve().then(() => _interopRequireWildcard(require('./node_modules/next/dist/cli/next-telemetry'))).then(i => i.nextTelemetry) }; const args = (0, _index.default)({// Types
'--version': Boolean, '--help': Boolean, '--inspect': Boolean,// Aliases
'-v': '--version', '-h': '--help'
}, { permissive: true });// Version is inlined into the file using taskr build pipeline
if (args['--version']) { console.log(`Next.js v${"11.0.1"}`); process.exit(0); }// Check if we are running `next <subcommand>` or `next`
const foundCommand = Boolean(commands[args._[0]]);// Makes sure the `next --help` case is covered
// This help message is only showed for `next --help`
// `next <subcommand> --help` falls through to be handled later
if (!foundCommand && args['--help']) {
console.log(`
Usage
$ next <command>
Available commands
${Object.keys(commands).join(', ')}
Options
--version, -v Version number
--help, -h Displays this message
For more information run a command with the --help flag
$ next build --help
`); process.exit(0);
} const command = foundCommand ? args._[0] : defaultCommand; const forwardedArgs = foundCommand ? args._.slice(1) : args._; if (args['--inspect']) throw new Error(`--inspect flag is deprecated. Use env variable NODE_OPTIONS instead: NODE_OPTIONS='--inspect' next ${command}`);// Make sure the `next <subcommand> --help` case is covered
if (args['--help']) { forwardedArgs.push('--help'); } const defaultEnv = command === 'dev' ? 'development' : 'production'; const standardEnv = ['production', 'development', 'test']; if (process.env.NODE_ENV && !standardEnv.includes(process.env.NODE_ENV)) { log.warn(_constants.NON_STANDARD_NODE_ENV); }; process.env.NODE_ENV = process.env.NODE_ENV || defaultEnv;// this needs to come after we set the correct NODE_ENV or
// else it might cause SSR to break
const React = require('react'); if (typeof React.Suspense === 'undefined') { throw new Error(`The version of React you are using is lower than the minimum required version needed for Next.js. Please upgrade "react" and "react-dom": "npm install react react-dom" https://nextjs.org/docs/messages/invalid-react-version`); }// Make sure commands gracefully respect termination signals (e.g. from Docker)
process.on('SIGTERM', () => process.exit(0)); process.on('SIGINT', () => process.exit(0)); commands[command]().then(exec => exec(forwardedArgs)).then(() => {
if (command === 'build') {// ensure process exits after build completes so open handles/connections
// don't cause process to hang
process.exit(0);
}
}); if (command === 'dev') { const { CONFIG_FILE } = require('./node_modules/next/dist/next-server/lib/constants'); const { watchFile } = require('fs'); watchFile(`${process.cwd()}/${CONFIG_FILE}`, (cur, prev) => { if (cur.size > 0 || prev.size > 0) { console.log(`\n> Found a change in ${CONFIG_FILE}. Restart the server to see the changes in effect.`); } }); }
//# sourceMappingURL=next.map
Any help would be greatly appreciated!
I faced the same issue while deploying my next.js app to staging server, and the solution was simple:
// rebuild and restart your app
npm i
npm run build
npm start
in my case it was due to .next folder was pointing to some old release.
I'm making a build script for my angular app in node. Please have a look at the snippet:
const fs = require('fs-extra');
const dev = process.argv[2] === 'dev';
const folder = process.argv[3];
if (folder && fs.existsSync(`./projects/${folder}`)) {
const execSync = require('child_process').execSync;
// ng build --prod --output-hashing=none OR ng build --source-map --output-hashing=none
let command;
if (dev) {
command = 'ng build --source-map --output-hashing=none ' + folder;
} else {
command = 'ng build --prod --output-hashing=none ' + folder;
}
// execSync(command, {stdio:[0, 1, 2]});
(async function build()
{
const files = [
];
const { promisify } = require('util')
const getFiles = async () => {
try {
const readdir = promisify(fs.readdir);
await readdir(`./dist/${folder}`, {withFileTypes:true}, (err, elements) => {
//handling error
if (err) {
return console.error('Unable to scan directory: ' + err);
} else {
elements.forEach(async element => {
if( !element.isDirectory() && /.*-es2015.js$/.test(element.name) ) {
files.push(`./dist/${folder}/${element.name}`);
console.log(`Pushing file: ./dist/${folder}/${element.name}`);
}
});
}
});
} catch (err) {
console.error(err);
}
}
await getFiles();
// We need a random number for voiding the cache with every new build
const random = [...Array(10)].map(()=>(c = (r = Math.random()).toString(36)[2]) && r>.5 ? c.toUpperCase():c ).join('');
// create directory if doesnt exists (not needed anymore): await fs.ensureDir(`../js/${folder}/dist`)
if (!dev && files.length) {
const concat = require('concat');
await concat(files, `./dist/${folder}/concatenated.${random}.js`);
}
console.log('Build complete');
}
)();
} else if (folder && !fs.existsSync(`projects/${folder}`)) {
console.log('Specified destination folder does not exists as a project');
}
else {
console.log('Please specify a destination folder such as app-name');
}
Well, the mysterious is that just after await getFiles() call, the execution halts, no error neither message anywhere is shown. I'm getting crazy investigating this.
Can anybody spot the issue?
Thanks
The main issue in your code is that you are not promisfying the readdir correctly.
Try this:
(async () => {
try {
const readdir = require('util').promisify(require('fs').readdir);
const elements = await readdir(`./dist/${folder}`, { withFileTypes: true });
await Promise.all(
elements.map(async (element) => {
if (!element.isDirectory() && /.*-es2015.js$/.test(element.name)) {
files.push(`./dist/${folder}/${element.name}`);
console.log(`Pushing file: ./dist/${folder}/${element.name}`);
}
})
);
} catch (error) {
console.error('Unable to scan directory: ' + err);
}
})();
You can of course keep your forEach while omitting the async instead of the map + async + Promise.all. The difference is is that the one I suggest is faster since it utilizes concurrency while forEach would work sequentially! But either one would work!
UPDATE: I believe I have found a (probably hacky) way to solve both problems, will post my updated code and solutions tomorrow for anyone interested.
I am trying to create a CLI application and decided I wanted to format the log output for a better user experience, including adding a verbose mode. I thus installed winston and managed to get it working how I wanted to. I then installed jest as I the app is getting more complex so I wanted to automate testing. I decided to make my first test for the logger as it was the last thing I was working on and I have immediately run into problems. My plan was to count the lines of output from the console log and check they were equal to ten: this would then mean I wouldn't have to hardcode in any error specific error messages which may change if I decide to change the log formatting at a later date. I would also like a test that changes the environment variable from dev to prod to ensure that it works correctly in both environments: does anyone know if this is possible? I am currently using dotenv for managing my environment variables and have added the relevant code to my jest config file so it will read the variables correctly. I have been reading through various stack overflow posts and the jest docs about mock functions in an attempt to solve these problems but it is all flying over my head. I don't strictly need these test to work to get on with my app as I'm pretty confident it is all working fine but it is frustrating to not be able to solve these problems and it would be useful to know in the future in case I do need to make a test that relies on the log output. Can anyone help?
set-log-to.js
const { createLogger, format, transports } = require('winston');
const { combine, printf, errors } = format;
const nodeEnvironment = process.env.NODE_ENV;
const cc = require('../constants/chalk-classes');
const {
fatal,
caveat,
victory,
error,
warn,
attempt,
success,
info,
debug,
plain,
} = cc;
const config = {
levels: {
fatal: 0,
caveat: 0,
victory: 0,
error: 1,
warn: 2,
attempt: 3,
success: 3,
info: 3,
verbose: 4,
debug: 5,
},
};
const formatting = combine(
errors({ stack: true }),
printf((infoObj) => {
const { level, message } = infoObj;
switch (level) {
case 'fatal':
return `${fatal(`${level}:`)} ${plain(message)}`;
case 'caveat':
return `${caveat(`${level}:`)} ${plain(message)}`;
case 'victory':
return `${victory(`${level}:`)} ${plain(message)}`;
case 'error':
return `${error(`${level}: ${message}`)}`;
case 'warn':
return `${warn(`${level}: ${message}`)}`;
case 'attempt':
return `${attempt(message)}`;
case 'success':
return `${success(message)}`;
case 'info':
return `${info(message)}`;
case 'verbose':
return `${plain(message)}`;
case 'debug':
return `${debug(level)}: ${plain(message)}`;
}
})
);
function setLevel(level) {
if (!level) {
if (nodeEnvironment === 'dev') {
return (level = 'debug');
} else {
return (level = 'warn');
}
} else {
return level;
}
}
function setLogTo(level) {
level = setLevel(level);
const log = createLogger({
levels: config.levels,
level,
transports: [
new transports.Console({
format: formatting,
}),
],
});
return log;
}
module.exports = setLogTo;
set-log-to.test.js
const setLogTo = require('../set-log-to');
test('All log levels function correctly', () => {
let log = setLogTo('debug');
log.fatal('This is fatal');
log.caveat('This is a caveat');
log.victory('This is a victory');
log.error('This is an error');
log.warn('This is a warning');
log.attempt('This is an attempt');
log.success('This is a success');
log.info('This is some info');
log.verbose('This is verbose');
log.debug('This is a debug');
expect(???).toEqual(10);
});
test('Logger does not print debug as standard', () => {
let log = setLogTo();
log.warn('This is a warning');
log.verbose('This is a verbose statement');
log.debug('This is a debug statement');
expect(???).toEqual(1);
});
test('Logger does not print info when set to error', () => {
let log = setLogTo('error');
log.info('This is an info statement');
log.error('This is an error')
expect(???).toEqual(1);
});
test('Dotenv works correctly', () => {
let log = setLogTo();
log.debug('This is a debug');
nodeEnvironment = 'prod';
log.debug('This us a debug');
expect(???).toEqual(1)
});
Ok, so Winston doesn't send messages to the console, or if it does it's the global console. Either way I figured that the best way around this would be to add a file logger to the console logger, subsequently reading the lines from the file rather than the console and then deleting the file after ever test. This then caused problems as standard Jest behaviour is to run its test simultaneously, so each test was attempting to access the same temporary file at the same time. This was easy to fix by passing the --runInBand option to jest in my package.json file which makes Jest run the tests sequentially.
To solve the environment variable problem, it turns out that Jest sets the NODE_ENV variable to 'test' when it starts up. I added a jest.resetModules() to the beforeEach statement allowing me to manually declare the environment at the start of each test. I stored the jest test environment in a constant at the start of the file so I could use this for the majority of the tests that did not require explicit environment variables to be set. I also created an afterAll() function to make sure that process.env was set back to the test environment for any subsequent tests.
Code:
package.json:
"logtest": "jest --runInBand ./src/helper/tests/set-log-to.test.js",
set-log-to.test.js:
const fs = require('fs');
const path = require('path');
const winston = require('winston');
let setLogTo = require('../set-log-to');
const { snipconDir } = require('../../constants/core-dirs');
const logTests = path.join(snipconDir, './temp/log-tests.txt');
const testEnv = process.env;
function createTestLog(level) {
let log = setLogTo(level);
log.add(
new winston.transports.File({
filename: logTests,
})
);
return log;
}
function allLogLevels(log) {
log.fatal('This is fatal');
log.caveat('This is a caveat');
log.victory('This is a victory');
log.error('This is an error');
log.warn('This is a warning');
log.attempt('This is an attempt');
log.success('This is a success');
log.info('This is some info');
log.verbose('This is verbose');
log.debug('This is a debug');
}
async function getLines() {
let data = await fs.promises.readFile(logTests);
let lines = data.toString().split('\n');
lines.pop();
return lines;
}
beforeEach(async (done) => {
jest.resetModules();
try {
await fs.promises.writeFile(logTests, '');
done();
} catch (err) {
console.log(err);
}
});
afterEach(async (done) => {
try {
await fs.promises.unlink(logTests);
done();
} catch (err) {
console.error('Failed to delete log-tests.js');
}
});
afterAll(() => {
process.env = testEnv;
});
test('When level is explicitly set to debug, all messages show', async () => {
process.env = testEnv;
let log = createTestLog('debug');
allLogLevels(log);
let lines = await getLines();
expect(lines.length).toEqual(10);
});
test('Standard behaviour shows messages from level 2 and below', async () => {
process.env = testEnv;
let log = createTestLog();
allLogLevels(log);
let lines = await getLines();
expect(lines.length).toEqual(5);
});
test('When explicitly set to error level, loggger displays all level 0 messages', async () => {
process.env = testEnv;
let log = createTestLog('error');
allLogLevels(log);
let lines = await getLines();
expect(lines.length).toEqual(3);
});
test('Verbose level displays messages from level 4 and below', async () => {
process.env = testEnv;
let log = createTestLog('verbose');
allLogLevels(log);
let lines = await getLines();
expect(lines.length).toEqual(9);
});
test('Development environment displays all messages', async () => {
process.env.NODE_ENV = 'dev';
let log = createTestLog();
allLogLevels(log);
let lines = await getLines();
expect(lines.length).toEqual(10);
});
test('Production environment displays messages from level 2 and below', async () => {
process.env.NODE_ENV = 'prod';
let log = createTestLog();
allLogLevels(log);
let lines = await getLines();
expect(lines.length).toEqual(5);
});
set-log-to.js:
const { createLogger, format, transports } = require('winston');
const { combine, printf, errors } = format;
const cc = require('../constants/chalk-classes');
const {
fatal,
caveat,
victory,
error,
warn,
attempt,
success,
info,
debug,
plain,
} = cc;
const config = {
levels: {
fatal: 0,
caveat: 0,
victory: 0,
error: 1,
warn: 2,
attempt: 3,
success: 3,
info: 3,
verbose: 4,
debug: 5,
},
};
const formatting = combine(
errors({ stack: true }),
printf((infoObj) => {
const { level, message } = infoObj;
switch (level) {
case 'fatal':
return `${fatal(`${level}:`)} ${plain(message)}`;
case 'caveat':
return `${caveat(`${level}:`)} ${plain(message)}`;
case 'victory':
return `${victory(`${level}:`)} ${plain(message)}`;
case 'error':
return `${error(`${level}: ${message}`)}`;
case 'warn':
return `${warn(`${level}: ${message}`)}`;
case 'attempt':
return `${attempt(message)}`;
case 'success':
return `${success(message)}`;
case 'info':
return `${info(message)}`;
case 'verbose':
return `${plain(message)}`;
case 'debug':
return `${debug(level)}: ${plain(message)}`;
}
})
);
function setLevel(level) {
if (!level) {
if (process.env.NODE_ENV === 'dev') {
return (level = 'debug');
} else {
return (level = 'warn');
}
} else {
return level;
}
}
function setLogTo(level) {
level = setLevel(level);
const log = createLogger({
levels: config.levels,
level,
transports: [
new transports.Console({
format: formatting,
}),
],
});
return log;
}
module.exports = setLogTo;
Need to know, how can I tackle the child process problem in Node JS. Basically, I need to convert the full pdf file into a jpeg. My process is getting killed. Most of the time files conversion is getting failed. How can I handle the long-running process? once the job is finished. I need to add there reference in the database. Could you please help.
const path = require('path');
const cp = require('child_process');
const src = path.join(__dirname, `/pdf-inputs/git.pdf`);
const exp = path.join(__dirname, `/jpg-outputs/git/git-%2d.jpg`);
const density = 300;
class Converter {
constructor(src, exp, den) {
this.src = src;
this.exp = exp;
this.density = den;
}
start() {
return new Promise((resolve, reject) => {
const child = cp.spawn('convert', ['-density', '300', `${this.src}`, `${this.exp}`], {
detached: true,
stdio: 'ignore',
});
console.log('process started =======> ', this)
child.stdout.on('data', data => {
console.log('process sucessful =======> ')
return resolve (data);
});
child.stderr.on('data', err => {
console.log('imagemagic process failed =======> ')
return reject(err);
})
child.on('error', (err) => {
console.log('child process error ========> ', err);
})
child.on('exit', (code, signal) => {
console.log(`child process exited with code: ${code} and signal ${signal}`)})
})
}
}
const c = new Converter(src, exp, density);
c.start().then(r => console.log('r ==> ', r)).catch(e => console.log('e ==> ', e));
~ Meet