how to handle multiple conncurrency request in node.js - node.js

I am trying to upload multiple images at simultaneously. in server side i have to
create one unique folder for to keep that images .so how to make wait request until one request complete and send response to client. i have tried this one but when i send response i am getting this error Can't set headers after they are sent.so suggest me good solution . i am waiting for urs reply.
when i upload five images , in server side i have to check whether folder is already exist or not. if it is not exist i have to create new folder for that five images and then i have to check that folder reference is already exist or not in mongodb.if it is not exist i have to store that folder reference in mongodb.and then i have to send response to client. but here when i upload five image, five request is going to server so request is doing that terms before complete one request so same folder reference is storing and also it is creating five folder for five image.
function myMiddleware(req, res, next)
{
console.info("inside myMiddleware");
var handler = function()
{
console.info("middleware redundant. ActionDone, calling next");
next();
};
EventManager.once("finished",handler);
if (actionDone !== "working")
{
actionDone = "working";
function doneWaiting(){
// console.log("finished");
actionDone = "finished";
EventManager.emit( "finished" );
}
setTimeout(doneWaiting, 500);
}

I think that what you need here is implementing a lock on the function that checks/creates the folder and does the database check/create.
Take a look at this article to see an example

Related

Why can't I set two different states from the same response object?

I'm getting an S3 signed URL response back to my client from my NodeJS server which handles communication with S3. I need the signed URL to upload images directly to S3 from my front end, and I need the image URL to display it from the S3 bucket. However I can't seem to set two different states with the same response object without getting a 403(Forbidden) error. I can set one state just fine and use it, but as soon as I try and set two using the same response object, it doesn't like it.
403Error
useEffect(() => {
async function getURL() { try {
await axios.get("imageRouter/S3Url").then((response) => {
setImageUrl(response.data.url.split("?")[0]);
setSignedUrl(response.data.url);
});} catch (error) {
console.log(error);
}}
getURL();},
[selectedFile]);
selectedFile is not a dependency of useEffect, the two dependencies are: setImageUrl and setSignedUrl and you should cache them so they won't change every time the state changes (using React.memo).
You should check the signed URL that is returned, by default the expiration is 15 minutes IIRC, so if you generate it once and use it multiple times you should make sure that it's not expired and if so - regenerate it. This can be checked by looking at the Expires parameter which shows up as a query param on the signed-url. We can use: https://www.epochconverter.com/ to translate it to a timestamp in a more readable format

Why node app crashes when req.files is null?

I have a frontend app(react) where the user can edit the product like price, description, delete images and add images.
The problem occurs when the user does not want to add new images.
Then on the backend(nodejs) req.files.newImages as I named it is null
and the backend crashes.
When I add one image or more everything works as it should because req.files.newImages has a value.
How to cover the case when the user does not want to add new images and prevent the app from crashing
I use express-fileupload and I use axios and put method to send data.
routes.put("/edit-product", (req, res) => {
console.log(req.files.newImages) // - result app crashed
}
Error in console: TypeError: Cannot read property 'newImages' of null;
You can simply check if there are any files like this:
if (req.files) {
// do something
}
Alternatively you can use optional chaining:
console.log(req.files?.newImages); // will log "undefined"
first check if it comes with console.log(req.files) with another name, if not, make sure you send it as "multipart" on the front-end side

How to have more then 30sec response timeout in heroku

Guys Heroku is terminating the req if the response takes more then 30sec to return, so is there any way I can wait for as long as the response would come back?
Well the user is uploading his file and I need to do something with the file in my server and after updates are done I will give a download link to the user. But mostly it takes more then 30 sec for the server to process the file so that the user need to wait for response
From the official Heroku Helpcenter : https://devcenter.heroku.com/articles/request-timeout
The timeout value is not configurable. If your server requires longer than 30 seconds to complete a given request, we recommend moving that work to a background task or worker to periodically ping your server to see if the processing request has been finished. This pattern frees your web processes up to do more work, and decreases overall application response times.
The short answer is : No, you can't change this configuration. I suggest you investigate why your application needs more than 30 seconds to process that request. If it takes longer than 10 seconds your really should consider the steps suggested in the Heroku Help Center 👆
Your Problem
You mention you need this for file processing. I understand that file processing could easily take longer than 30 seconds. Normally what I would do is to just create some sort of task reference and keep it in a database along with a status ("processing", "finished", "failed") - also store the original file and then just end the request of the user. This shouldn't take long. Then process the task ... with another endpoint or websocket connection the user could check if the task has been fullfilled.
Use a Task Queue
The following is just a basic interpretation of a solution - it's not meant for copy & pasting as it depends on so many things.
Routes (Endpoints)
Basically you need to have 3 routes in your backend. One for uploading the file, one for downloading the processed file and one for checking the status of the task.
1. Upload
app.post('/files', /* some middleware e.g. multer */, async (req, res) => {
// This is your upload controller
// I assume at this point the file has been uploaded and
// req.file contains a reference to the uploaded file.
// create new process task and add to queue
const task = await createNewTask(req.file);
queue.push(task);
// now a task has been created, but the user
// doesn't need to wait for it to finish
// so let's end the request here.
return req.status(200).json(task);
});
2. Check Status
app.get('/task/:id', async (req, res) => {
// From uploading a file in the first step, you'll
// get back a task id. Use the task id to check on
// the status.
const task = await getTask(req.params.id);
if (!task) {
return res.status(404).end();
} else {
return res.status(200).json(task);
}
});
The task can include informations like status, progress percentage, original filename, new filename or even a download link to the processed file once it's finished. Status could be something like pending, processing, finished or failed.
3. Download
app.get('/file/:filename', (req, res) => {
return req.status(200)
.sendFile('./path/to/file/' + req.params.filename);
});
Notes
It might be a good idea to rename the incoming files with a random id like a uuid. So it's easier to work with them in the automation process. Also the random id could be used for the task id at the same time.
It's up to you how big you want to go with this. For the task queue there are many different libraries to help you out with it. It could be an in-memory queue or one that's backed with a database.

Error: Can't set headers after they are sent only on page refresh

I have this problem only when I try refresh the page and I can not solve it, I tried everything but still happens the same. It began to happen when I add socket.io at the project. The project run in several servers which are connected one each other throught sockets.
TEST CASES: When I render the page, at the first time everything goes well but, if I refresh the same page, I get this error:
ERROR: "Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)"
ATTENTION: when get in IF() and send "return res.end('The Activation Code is INVALID!');" it DOESN'T HAPPEND! I refresh it and refresh it and everything goes well. My problem is in the RENDER.
MY CODE BELOW:
activationUser = function(req,res,next){
var data = {
activationCode : req.params.activationCode,
now : new Date().valueOf(),
ip : req.connection.remoteAddress,
fId : frontalId
}
socketCore.emit('activationUser', data);
socketCore.on(frontalId + 'activationUserResp', function(data){
if(data.msg == "CHECKED!"){
next();
}else{
return res.end(data.msg);
}
});
}
router.get('/activationUser/:activationCode',activationUser,function(req,res){
var data = {
activationCode : req.params.activationCode,
fId : frontalId
}
socketCore.emit('step2', data);
socketCore.on(frontalId + 'step2Resp', function(data){
if(data.msg == 'err'){
return res.end('The Activation Code is INVALID!');
}else{
return res.render('registro2', {title: 'title | '+ data.name + ' ' + data.lastname, user:data});
}
});
});
Thank you!
The particular error you are getting happens when you try to send anything on the res object after the complete response has already been sent. This often occurs because of errors in asynchronous logic. In your particular case, it apepars to be because you are assigning a new event handler with socketCore.on() every single time the router is hit. Those event handlers will accumulate and after the first time the route is hit, they will execute multiple times triggering the sending of multiple responses on the same response object, thus trigger that error.
The main ways to fix your particular problem are:
Use .once() instead of .on() so the event handler automatically removes itself after being triggered.
Manually remove the .on() event handler after you get the response.
Move the event handler outside of the route so it's only ever installed once.
In your particular case, since socketCore is a shared object available to all requests, it appears that you also have a race condition. If multiple users trigger the '/activationUser/:activationCode' route in the same general time frame, then you will register two event handlers with socketCore.on() (one for each route that is hit) and you will do two socketCore.emit('step2', data);. But, you have no way of associating which response belongs with which request and the two responses could easily get mixed up - going to the wrong request.
This highlights how socket.io connections are not request/response. They are message/answer, but unless you manually code a correspondence between a specific message request and a specific answer, there is no way to correlate which goes with which. So, without assigning some particular responseID that lets you know which response belongs to which message, you can't use a socket.io connection like this in a multi-user environment. It will just cause race conditions. It's actually simpler to use an HTTP request/response for this type of data fetching because each response goes only with the request that made it in the HTTP architecture.
You can change your architecture for making the socketCore request, but you will have to manually assign an ID to each request and make sure the server is sending back that ID with the response that belongs to that request. Then, you can write a few lines of code on the receiving side of things that will make sure the right response gets fed to the code with the matching request.

Unable to upload file to Box using Node

I'm having a really tough time getting my files to upload to box using Node.js.
Every single time I attempt to, I get the following error:
Error: cannot POST /api/2.0/files/content (400)
Here is the relevant code. I've already double checked that this.options.auth contains the required tokens, etc. The parent_id folder is the root folder, so '0'. The filepath is a stream, which is totally fine.
request.post('https://upload.box.com/api/2.0/files/content')
.set('Authorization', this.options.auth)
.field('parent_id', folder)
.attach('filename', filepath)
.end(function (res) {
if (res.error) {
return callback('Error: '+res.error.message);
}
callback(null, res.body);
});
Any ideas?
HTTP status code 400 is used for a bad request. One thing to check is that the parameters you are supplying are all valid and that you haven't forgotten any required parameters. Looking at the Box API getting-started doc, it appears that what you are calling parent_id should be just parent. If it still doesn't work, check for other similar issues too, of course.

Resources