Why does this behaviour with nodejs and child process happen? - node.js

What am I trying to do?
I want to clone multiple git repositories from nodejs.
How do I achieve that?
First I have this method in a separate file:
const exec = require("child_process").exec;
const { printError } = require("./printers");
function execute(command) {
console.log(`Running command: ${command}`);
let result = "";
let savedError = undefined;
return new Promise((resolve, reject) => {
const proc = exec(command, function (error, stdout, stderr) {
savedError = savedError || stderr || error;
result += stdout;
});
proc.on("close", (code) => {
if (code !== 0) {
console.error(
[
"================================================================",
`Command ${command} failed.`,
`Status code: ${code}`,
`Error message: ${savedError}`,
`Output: ${result}`,
"================================================================",
"",
].join("\n")
);
reject(result);
} else {
resolve(result);
}
});
});
Then I use it in my main module (code is abbreviated and bit simplified just so you can get the point:
const repoUrls = ["url1", "url2"]; // imagine these are real urls
async function main() {
const copyOfUrls = [...repoUrls];
while (copyOfUrls.length) {
try {
await execute(
`git clone ${copyOfUrls[0]} repositories/${repoUrlFileFriendly(
copyOfUrls[0]
)}`
);
console.log('fun fact - this console log never happens');
copyOfUrls.shift()
} catch (error) {
console.error("Failed to clone, see error:", error);
}
}
}
What is the problem?
Well, code works BUT after cloning first repo, the process exits (both the child process and the main one) and second repository is never even attempted to be cloned. (note the "console.log('fun fact - this console log never happens');").

Related

Catching NodeJS errors using a discord.js command handler

I'm creating a Discord bot, but have some problems catching the errors that my bot sends.
I'm using a custom command handler, that is working pretty well.
Fs.readFile(`./database/prefixes/prefixes.json`, "utf8", (err: Error, data): void => {
data = JSON.parse(data);
const prefix: string = data[message.author.id] == undefined ? "ma!" : data[message.author.id];
const msg: string = message.content;
const args: string[] = message.content.slice(prefix.length).trim().split(" ");
const cmd: string = args.shift().toLowerCase();
if (!msg.startsWith(prefix)) {
return checkCustomCommands();
}
let ops: {} = {
queue: queue
}
try {
require(checkFolders(cmd)).run(Client, message, args, ops); // maybe catching just there?
Logger.log(`${message.author.tag} just used the ${cmd} power in ${message.guild.name}.`);
} catch (err) {
Logger.log(`The command ${message.author.tag} tried to call in ${message.guild.name} doesen't seem to exist.`);
}
});
function checkCustomCommands() {
let content = JSON.parse(Fs.readFileSync('./database/commands/commands.json', 'utf8'));
try {
if (content[message.guild.id][message.content] == undefined) {
return;
} else {
message.channel.send(content[message.guild.id][message.content]);
}
} catch (err) {
return;
}
}
function checkFolders(command) {
let folders = ["moderation", "fun", "music", "info", "game"];
var files: string[];
var finalPath: string;
folders.forEach(folder => {
files = Fs.readdirSync(`./src/commands/${folder}`);
files.forEach(file => {
if (file.split(".")[0] == command) {
return finalPath = `./../commands/${folder}/${file.split(".")[0]}.js`;
}
});
});
return finalPath;
}
But sometimes, my bot sends various errors that I can't catch into the commands files, resulting in my bot being shutdown. Is there any way to prevent that inside the command handler, or anything I can do to catch these errors?
Thanks a lot, I can provide more code if needed, even though the biggest chunk of the command handler is just there ^
I'm quite late to this, but I feel like I should answer my own question, now that I'm able to do so haha
The main way to catch these errors is by listening to the unhandledRejection event, via Node process.
Here's how I did it:
async function handleRejections() {
process.on("unhandledRejection", (error: Error) => {
const errorEmbed: Discord.MessageEmbed = new Discord.MessageEmbed()
.setDescription("<:no:835565213322575963> An error has been detected... \n" + `\`\`\`${error.stack}\`\`\``)
.setTimestamp()
.setFooter(client.user.username, client.user.displayAvatarURL())
.setColor("DARK_RED")
logError(client, errorEmbed);
});
}
Be sure to call the function at the very beginning of the project code, even before the bot starts.
I personally log these errors into a Discord channel, on my server, so that I can check them easily. That's it! Hope that helps. Keep on coding :D

"TypeError: Cannot read property 'url' of undefined", and wrong command behavior. - discord.js

I've been working on a "artwall" bot with, basically write to .json file command. I want for the bot to get the first message attachment, get it's url and save it to save.json.
If there's a an attachment present, everything works fine, but if the command was initiated with a url or without any arguments at all, it gives this error:
TypeError: Cannot read property 'url' of undefined
Here's the command code:
const fs = require('fs');
// Export code for command.
module.exports = {
// In name type name of this command to execute it.
name: 'done',
// In description type description.
description: 'N/A',
// In execute() {...} circle brackets type execution parameters.
execute(client, message, args) {
// Type command code here.
const safety = JSON.parse(fs.readFileSync('./assets/save.json', 'utf8'));
const currentdeg = JSON.parse(fs.readFileSync('./assets/currentDEBUG.json', 'utf8'));
// const attache = JSON.parse(fs.readFileSync('./assets/attach.json', 'utf8'));
if(safety == 'no') {
if(currentdeg == 'not claimed') {
message.channel.send('The wall is not claimed yet. Claim it by using `wol claim`');
}
else if(currentdeg == message.author.id) {
const Attachment = (message.attachments).array();
console.log(Attachment);
if (Attachment == []) {
if (!args) {
message.reply('there\'s no image present. Make sure you attached one message or used url.');
return;
}
else {
fs.writeFile('assets/currentDEBUG.json', JSON.stringify('not claimed', null, 2), err => {
// Checking for errors
if (err) throw err;
console.log('Done writing (claim)');
});
fs.writeFile('assets/attach.json', JSON.stringify(args[0], null, 2), err => {
// Checking for errors
if (err) throw err;
console.log('Done writing (attache)');
});
}
}
// stuff
fs.writeFile('assets/currentDEBUG.json', JSON.stringify('not claimed', null, 2), err => {
// Checking for errors
if (err) throw err;
console.log('Done writing (claim)');
});
fs.writeFile('assets/attach.json', JSON.stringify(Attachment[0].url, null, 2), err => {
// Checking for errors
if (err) throw err;
console.log('Done writing (attache)');
});
}
else {
// stuff
message.channel.send('The artwall was claimed by someone else already. Wait for them to finish their work.');
}
}
else {
message.channel.send('The artwall is locked right now. Please wait for the next event!');
}
},
};
Thanks in advance!

Function call hangs

I have the following code in my index.js file. This was my attempt to implement an external task worker for Camunda in node js after cloning this repo.
var Workers = require('camunda-worker-node');
var Backoff = require('camunda-worker-node/lib/backoff');
try {
console.log('In try ');
console.log(Backoff)
var engineEndPoint = process.env.ENGINE_URL || 'http://localhost:8080/engine-rest';
}
catch (e) {
console.log(e)
}
console.log("Out of try");
var uuid = require('uuid');
var workers = new Workers(engineEndPoint);
try {
Backoff(workers);
}
catch (e) {
console.log(e);
}
workers.subscribe('FightTribe', ['name'], function (context, callback) {
console.log("in worker subscribe");
if (Math.random() > 0.9) {
console.log('German Tribe Fighter, The Battle is lost.');
return callback(null, {
variables: {
legionStatus: "defeated"
}
});
}
console.log('German Tribe Fighter, The Battle is WON.');
callback(null, {
variables: {
legionStatus: 'Victorious'
}
})
});
My camunda process engine is up and running. On starting up index.js the process hangs at the function call Backoff(workers).
In an attempt to debug i placed console.log("in worker subscribe") in workers.subscribe, but the execution never reaches there.
I have attached my working directory. I am not sure what the issue is.

Node js - Combine two streams in parallel way

I need combine two streams in parallel way. I want to use these streams to write into two files some generated information.
I have done the first stream (stream1). It looks like this:
'use strict';
var fs = require('fs');
var stream1 = fs.createWriteStream("random1.txt");
let ln = 1000000;
let j = 0;
function generateRandom()
{
var reslt = true;
do {
ln--;
j++;
if (ln === 0) {
stream1.write(...write randon number...);
stream1.end();
} else {
reslt = stream1.write(...write randon number...);
}
} while (ln > 0 && reslt);
if (ln > 0) {
stream1.once('drain', generateRandom);
}
}
stream1.on('error', (err) => {throw err;});
var stream1Promise = new Promise((resolve, reject)=>{
try {
generateRandom();
});
} catch (error) {
reject(error);
}
});
stream1Promise
.then(function(callback) {
if (typeof callback === 'function') {
callback();
}
}, function(error) {
console.log("Error occurred: ", error);
stream1.end();
});
But I don't understand how to add another one stream stream2 so that it writes different random information to another file.
I've tried to use process.nextTick in callback of stream1.write to switch my streams, but I get all time "FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory" error.
Could anyone help me?
Thanks.

Catching ECONNRESET error from spawned Node process

I am using the sftps NPM to connect to a SFTP server using username/password authentication and upload a file. This works beautifully when successful; however, if provided invalid authentication information, after several minutes it emits an ECONNRESET error which crashes my entire application.
Looking at the source of the sftps module, it appears to use child_process.spawn to run the shell commands, and looks like it should be capturing any errors gracefully:
var sftp = spawn(shellCmd, shellOpts);
var data = "";
var error = "";
sftp.stdout.on('data', function (res) {
data += res;
});
sftp.stderr.on('data', function (res) {
error += res;
});
function finished(err) {
error = error.split('\n').filter(function(line) {
if (/^Connected to /.test(line)) return false;
return true;
}).join('\n');
data = data.split('\n').filter(function(line) {
if (/^sftp> /.test(line)) return false;
return true;
}).join('\n');
if (callback) {
if (err) {
callback(err, { error: error || null, data: data });
} else if (error) {
callback(null, { error: error, data: data });
} else {
callback(null, { error: null, data: data });
}
callback = null;
}
}
sftp.on('error', finished);
sftp.on('exit', function (code) {
if (code === 0) {
finished();
} else {
finished('Nonzero exit code: ' + code);
}
});
sftp.stdin.write(cmdString, 'utf8');
It looks like it has hooked into the stderr stream as well as capturing the error and exit events on the sub-process.
What else can I do to capture this ECONNRESET error and log it without killing the application?
Don't know if you're having the same problem that I was having, but I eventually solved it by attaching an event to stdin.on("error"). You could try this to see if that's the problem:
sftp.stdin.on("error", function (e)
{
console.log("STDIN ON ERROR");
console.log(e);
});

Resources