Nodejs Socket hang up & ECONNRESET - HTTP post req

2019-04-18 04:43发布

问题:

I am using a node server to handle all my push notifications services like gcm and apn.

I have 2 different servers. One is running Meteor and another is running Node.JS to handle push notifications. (Both are different servers)

My main app runs on the Meteor server.

I make an HTTP post request to the node.js server to send my notifications.

Usually it works fine, but sometimes on the Meteor server I get this error whenever I call the node.js server:

socket hang up\n    at Object.Future.wait (/home/myPc/.meteor/packages/meteor-tool/.1.1.10.ki0ccv++os.linux.x86_64+web.browser+web.cordova/mt-os.linux.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:398:15)\n    at Object.<anonymous> (packages/meteor/helpers.js:119:1)\n    at Object.HTTP.call (packages/meteorhacks_kadira/lib/hijack/http.js:10:1)\n    at Object.sendPushNotificationsMeteorServer (server/pushNotifications.js:249:1)\n    at server/classes/pushNotifications.js:244:1\n    at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)\n    at packages/meteor/timers.js:6:1\n    at runWithEnvironment (packages/meteor/dynamics_nodejs.js:110:1)\n    - - - - -\n    at createHangUpError (http.js:1473:15)\n    at Socket.socketOnEnd [as onend] (http.js:1569:23)\n    at Socket.g (events.js:180:16)\n    at Socket.emit (events.js:117:20)\n    at _stream_readable.js:944:16\n    at process._tickCallback (node.js:448:13)',
details: { [Error: socket hang up] stack: [Getter] },
data: { [Error: socket hang up] stack: [Getter] },
user: null,
userId: null,
toString: [Function] },
user: null,
userId: null,
toString: [Function] }

OR

 Error: read ECONNRESET
     at Object.Future.wait (/home/mbm/.meteor/packages/meteor-tool/.1.1.10.12ml1tp++os.linux.x86_64+web.browser+web.cordova/mt-os.linux.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:398:15)
     at Object.call (packages/meteor/helpers.js:119:1)
     at Object.sendHttpCall (server/pushNotifications.js:249:1)
     at server/pushNotifications.js:244:1
     at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
     at packages/meteor/timers.js:6:1
     at runWithEnvironment (packages/meteor/dynamics_nodejs.js:110:1)
     - - - - -
     at errnoException (net.js:905:11)
     at TCP.onread (net.js:559:19)

Here is my Node.JS server code:

realFs                = require('fs');
var gracefulFs        = require('graceful-fs');
gracefulFs.gracefulify(realFs);

var http              = require('http');
var express           = require('express');
var app               = express();

var path              = require("path");

configClass           = require('./classes/config.js').configClass;
helperClass           = require('./classes/helper.js').helperClass;
pushNotificationClass = require('./classes/pushNotification.js').pushNotificationClass;

var hostname          = 'http://localhost'; 
var port              = 6000;

var bodyParser        = require('body-parser');

nodeGcm               = require('node-gcm');
apn                   = require('apn');
apnService            = new apn.Connection(helperClass.getAPNOptions());

// -- BODY PARSER -- //
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));

process.on('uncaughtException', function (err) {

  console.error(err);
  console.log("Node NOT Exiting...");
});

// All post requests
app.post('/', function(req, res){

  try {

    var response = JSON.parse(req.body.pushNotificationApiParams);
    var callType = req.body.callType;

    switch (callType) {
        case 'systemPushNotifications':
            return pushNotificationClass.sendPushNotificationsV2(response);
        break;
    } 
  }
  catch(e){

    console.dir(e.stack);
    realFs.appendFile('errorLogs/'+helperClass.getCurrentDateFormated()+'.log', helperClass.formatLog('Exception in main Post Method  : '+e.stack) , function (err) {
      if (err) throw err;
    });
  }

  res.send("OK");
});



app.listen(port, function () {
  console.log('Listening at '+hostname+':'+port);
});

And here is my code from Meteor side, where I am make HTTP post request to node js server:

var headers = {
   'Content-Type' : 'application/x-www-form-urlencoded'
};

var postFields = {
   callType : 'systemPushNotifications',
   pushNotificationApiParams  : JSON.stringify(pushNotificationApiParams)   // contains push notifications data                 
};

HTTP.call("POST", 'http://localhost:6000', { params:postFields, headers:headers });

Can anyone guide me in the right direction? Also I would really appreciate to know some good practices as well.

Also

There is one more issue I am facing. My node.js server exits after like 24 hours. I don't know why does that happens. It exits without any error or exception in the terminal console. I have to restart it each time.

回答1:

Considering the ECONNRESET error usually occurs when the *other side of the TCP connection is closed abruptly.

  • In case of your application it may be due to the overloading of the server and simply kills the connection as a return which in the similar way blocks the connection to your meteor server

To get more info about the error as mentioned in this thread. To handle the error you must use an event listener to it to show the full stack traces of it

As mentioned in this thread by Farid Nouri Neshat

To have one listener for a group of calls you can use domains and also catch other errors on runtime. Make sure each async operation related to http(Server/Client) is in different domain context comparing to the other parts of the code, the domain will automatically listen to the error events and will propagate it to it's own handler. So you only listen to that handler and get the error data.

but since the domain have already been deprecated you should use clusters as mentioned here in the docs which uses server.listen(message) and the server.listen(handle)

or you can also use NODE_DEBUG=net or use strace

Update

For the server disconnect i think the error might be in your handling of the bodyparser.For a bad json file the error is uncaught.

Node's default action following an uncaught exception is to exit(crash) on the process.

Handling of bodyparser for a json file can be done in the following way.

var parseJson = bodyPaser.json();

app.use(function (req, res, next) {
    req.getBody = function (callback) {
        parseJson(req, res,function (err) {
          callback(err, req.body);
        });
    };
    next();
}); 

Reference taken from the GITHUB open issue's here

Update 2

Basically the socket hangup means that the socket doesn't end the connection within the specified time period

According to the source you can see that it occurs if the server never sends the response

.This error should be caught and handled by either

  • retrying to the request.
  • handling it later by setting more time period or put res.end() at the end of your function to end the connection.
  • or you can use the [http.get()][8] with the get requests which will automatically call the req.end() function

Hope it might help you a bit! Cheers!



回答2:

Ok I found the issue myself here. Its in the node server code. I put return in a switch statement which is not a valid way to return a response in express, so I just removed the return from:

Before:

switch (callType) {
   case 'systemPushNotifications':
      return pushNotificationClass.sendPushNotificationsV2(response);
   break;
}

Now:

switch (callType) {
   case 'systemPushNotifications':
      pushNotificationClass.sendPushNotificationsV2(response);
   break;
}

The above return was terminating the code before the: res.send("OK");