Parallel processing fails in node js - node.js

I have the below piece of code which hits a url for each user id in loop.
var requests = [];
for (let i = 0; i < userids.length; i++) {
requests.push(this.getUserData(authToken, userid[i]));
}
const userdetails=await (Promise as any).allSettled(requests);
The code fails for some requests and returns error for some requests. But when the same code is implememnted using sequential processing it works and returns correct data. Below is the code for the same
var requests:any=[]
for (let i = 0; i < userids.length; i++) {
requests.push(await this.getUserData(authToken, userid[i]));
}
How shall I fix it?

Related

How do you spread a lot of requests over time in nodejs?

I'm working on a backend that has to request data from Moralis (web3), but how can I spread the requests in time so that I don't exceed the max requests each minute and so it doesn't time out. Right now I'm calling a function within a for loop.
const allContractInfo = await Moralis.Web3API.token.getAllTokenIds({ address: address, chain: "rinkeby", });
const nftItems = allContractInfo.result;
for(let i = 0; i < allContractInfo.total; i++){
UpdateItemAuction(nftItems[i].token_address, nftItems[i].token_id)
}
This is just an example to fix this problem. Hope you can find better solutions.
const allContractInfo = await Moralis.Web3API.token.getAllTokenIds({ address: address, chain: "rinkeby", });
const nftItems = allContractInfo.result;
for(let i = 0; i < allContractInfo.total; i++){
setTimeout(function() {
UpdateItemAuction(nftItems[i].token_address, nftItems[i].token_id);
}, i*1000);
}
This will ensure that requests are fired 1/sec.

looping through an array of objects using node js and mongodb

i am new with using mongodb and node am trying to loop through an array of objects from my database and display only the objects using a res.json, in my console.log it displays all the object, but in my postman using res.json it displays only one object please help
MY CODE
const course = res.GetUserDT.coursesHandled;
for (let index = 0; index < course.length; index++) {
console.log(course[index]);
}
const course = res.GetUserDT.coursesHandled;
for (let index = 0; index < course.length; index++) {
res.json(course[index]);
}
my console output
{ courseCode: '2103' }
{ courseCode: '2012' }
{ courseCode: '2062' }
my postman output
{ courseCode: '2103' }
Hi and welcome to Stackoverflow.
The Problem here is that res.json() sends a an immidiate response to the requestor - meaning a response is sent already within the first iteration of your for-loop.
I am also wondering why you need that loop - as you are not doing anything within it. So why don't you just send the array immidiately like so:
res.json(res.GetUserDT.coursesHandled);
You can only send res.json once.
To send all of them together you can create an array, push all the objects in the array and send it back as a response.
let arrayToReturn = []
for (let index = 0; index < course.length; index++) {
arrayToReturn.push(course[index])
}
res.json(arrayToReturn);
Update
#David's answer is the most accurate solution i.e just directly send the array as a response instead of looping
res.json(res.GetUserDT.coursesHandled);
Assuming that is express, res.json() will send the data and end the response.
try something like:
const responseArray = [];
for (let index = 0; index < course.length; index++) {
responseArray.push( course[index] );
}
res.json(responseArray);

calling websocket send function from within .then() in nodejs

i have a promise that resolves a JSON object with some config data. i want to access this data upon pressing the "send config" button in my HTML client. the communication is done through a websocket connection in nodejs. so the websocket server receives a message that says "send config" from the client and the server is supposed to respond with the config.
code:
showMsg = function (MSGOBJ) {
var parsedOBJ = JSON.parse(MSGOBJ);
//console.log(parsedOBJ.content);
for (var i = 0; i < connections.length; i++) {
switch(parsedOBJ.type) {
case "text":
console.log("Received: " + parsedOBJ.content)
connections[i].sendUTF('{ "type":"text", "content":"Server ready."}')
break;
case "config":
console.log("Received:1 " + parsedOBJ.content)
console.log("Sending config" )
var getConfig = KRequests.getKConfig;
var configOBJ;
getConfig.then(function(result) {
configOBJ = result
});
connections[i].send('{ "type":"config", "content":'+JSON.stringify(configOBJ)+'}');
break;
}
}
}
i know configOBJ would be undefined if i use it outside of the chain, but just to give you an idea of what i want to do. and also if i move the send() inside the chain, it would cause this error: "UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'send' of undefined"
You have two issue one is that you should use:
getConfig.then(function(result) {
console.log(connections[i])
connections[i].send('{ "type":"config", "content":'+JSON.stringify(configOBJ)+'}');
});
The other is that:
for (var i = 0; i < connections.length; i++) {
should be:
for (let i = 0; i < connections.length; i++) {
Or if you don't have let which you should if you are using a recent node that supports more than ES5. You will have to use a IIFE like this:
for (var i = 0; i < connections.length; i++) {
(function (i) {
// put the loop body here
})(i);
}

nodejs do something after multiple functions complete

I'm having a problem that I can't seem to get around.
Imaging the following
if (users) {
for (var i = 0; i < users.length; i++) {
apiData.users = getUserDetails(users[i]);
}
}
and
if(profiles) {
for (var i = 0; i < profiles.length; i++) {
apiData.profiles = getProfileDetails(users[i]);
}
}
now, only once both of those blocks of code have been completed (i.e. the API calls have returned the results that are required), would I like to do something like this
for (var i = 0; i < users.length; i++) {
saveUserProfile(apiData)
}
Normally I handle a situation like this by wrapping the first block of code in a function that returns a callback and then running the third function afterwards, but how can I do this when there are effectively 2 separate operations happening?
To be clear, I would like to avoid saving users and profiles separately, there are various reasons for this.
I would like to know if there is any standard way of handling a situation like this as there may or may not be users or profiles, so using callbacks seems like it will not work?
You can use async module to achieve this.
Use async.parallel() function since your first and second snippets do not depend on each other, and can run asynchronously, but you wish to make third snippet run when first and second are done executing.
Assuming users, profiles, and apiData are already declared, your code would look like
function func1(callback){
if (users) {
for (var i = 0; i < users.length; i++) {
apiData.users = getUserDetails(users[i]);
}
}
//invoke callback
}
function func2(callback){
if(profiles) {
for (var i = 0; i < profiles.length; i++) {
apiData.profiles = getProfileDetails(users[i]);
}
}
//invoke callback
}
var asyncfunc = [];
asyncfunc.push(func1);
asyncfunc.push(func2);
async.parallel(asyncfunc,function(err,result){
//result is an array which receives the second argument of each function's callback.
for (var i = 0; i < users.length; i++) {
saveUserProfile(apiData)
}
})
EDIT
PS: you can also use async.series() here. Both are equivalent in this case, since the functions handled by async.parallel() here do not use timers neither perform I/O tasks.
The callback in each function inside the array takes two arguments. First argument represents error, which is null if there are no errors, second represents the result of the function, which is passed to the second argument of the async.parallel() function's callback.

async in for loop in node.js without using async library helper classes [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I am a beginner to node.js. I was trying out the examples from the 'learnyounode' tutorial. I am trying to write a program that takes three url parameters and fetches some data from those urls and displays the returned data in the order in which the urls were provided.
var http = require('http');
var bl = require('bl');
var url = [];
url[0] = process.argv[2];
url[1] = process.argv[3];
url[2] = process.argv[4];
var data = [];
var remaining = url.length;
for(var i = 0; i < url.length; i++){
http.get(url[i], function (response){
response.setEncoding('utf8');
response.pipe(bl(function (err, chunk){
if(err){
console.log(err);
}
else{
data[i] = chunk.toString();
console.log(data[i]);
remaining -= 1;
if(remaining == 0) {
for(var j = 0; j < url.length; j++){
console.log(data[j]);
}
}
}
}));
});
}
I have two console.log statements in the program. The output i get is as follows:
It'll be chunder where lets throw a ford. We're going durry where mad as a cooee
.
Shazza got us some apples with come a strides. Mad as a swag when get a dog up y
a roo. It'll be rapt piece of piss as cunning as a trackie dacks.
As cross as a bogged with watch out for the boardies. As cunning as a digger fla
min lets get some roo bar. As dry as a piker piece of piss he hasn't got a joey.
Lets throw a strides mate we're going digger.
undefined
undefined
undefined
It seems like the data is correctly fetched and stored in the 'data' array but it still displays undefined.
Any idea why this is happening?
Thanks in advance!
This is a very common issue in async programming in node.js or even in the browser. A main issue you have is that the loop variable i will not be what you want it to be some time later when the async callback is called. By then, the for loop will have run to the end of its loop and i will be at the end value for all response callbacks.
There are numerous ways to solve this. You can use a closure to close over the i value and make it uniquely available to each callback.
var http = require('http');
var bl = require('bl');
var url = [];
url[0] = process.argv[2];
url[1] = process.argv[3];
url[2] = process.argv[4];
var data = [];
var remaining = url.length;
for(var i = 0; i < url.length; i++){
// create closure here to uniquely capture the loop index
// for each separate http request
(function(index) {
http.get(url[index], function (response){
response.setEncoding('utf8');
response.pipe(bl(function (err, chunk){
if(err){
console.log(err);
}
else{
data[index] = chunk.toString();
console.log(data[index]);
remaining -= 1;
if(remaining == 0) {
for(var j = 0; j < url.length; j++){
console.log(data[j]);
}
}
}
}));
});
})(i);
}
If you do much node.js programming, you will find that you probably want to learn how to use promises because they are very, very handy for controlling the flow and sequence of async operations.

Resources