NodeJS -> Error: write after end (only after first request) - node.js

In my express app i have the route below:
router.get('/generatedData', function (req, res) {
res.setHeader('Connection' , 'Transfer-Encoding');
res.setHeader('Content-Type' , 'text/html; charset=utf-8');
res.setHeader('Transfer-Encoding' , 'chunked');
var Client = someModule.client;
var client = Client();
client.on('start', function() {
console.log('start');
});
client.on('data', function(str) {
console.log('data');
res.write(str);
});
client.on('end', function(msg) {
client.stop();
res.end();
});
client.on('err', function(err) {
client.stop();
res.end(err);
});
client.on('end', function() {
console.log('end');
});
client.start();
});
On first call everything works fine (console)
We've got ourselves a convoy on port 3000
start
data
data
data
data
data
...
data
end
GET /generatedData 200 208.426 ms - -
I get all the data and res.end() is being called and successfully closes the request.
The problem starts after first request. I make the exact same request (new one of course) and i get the following error (console):
start
data
data
data
events.js:160
throw er; // Unhandled 'error' event
^
Error: write after end
at ServerResponse.OutgoingMessage.write (_http_outgoing.js:439:15)
at Client.<anonymous> (/Users/xxxx/projects/xxxx/routes/index.js:33:17)
at emitOne (events.js:96:13)
at Client.emit (events.js:188:7)
at FSWatcher.<anonymous> (/Users/xxxx/projects/xxxx/lib/someModule.js:116:32)
at emitTwo (events.js:106:13)
at FSWatcher.emit (events.js:191:7)
at FSEvent.FSWatcher._handle.onchange (fs.js:1412:12)
[nodemon] app crashed - waiting for file changes before starting...
This happens without res.end() being called.
I manage to get some data before the crash.
How can i get this error without res.end() being called at all?
Do i somehow save the previous res instance?
Thanks,
Asaf

Have the same problem. My module was extened by EventEmitter and each time i catch event in router - it stays there, end on second call there are two eventlisteners not one. Setting "once" instead of "on" - worked for me.
client.once('start', function() {
console.log('start');
});
instead of
client.on('start', function() {
console.log('start');
});

Related

Unable to gracefully close http2 client stream in nodejs

I have the following code which has been heavily inspired from nodejs official documentation of a client-side example
import http2 from 'http2';
// The `http2.connect` method creates a new session with example.com
const session = http2.connect('https://somedomain.com');
// Handle errors
session.on('error', (err) => console.error(err))
const req = session.request({
':authority': 'somedomain.com',
':path': '/some-path',
':method': 'GET',
':scheme': 'https',
'accept': 'text/html',
});
// To fetch the response body, we set the encoding
// we want and initialize an empty data string
req.setEncoding('utf8')
let data = ''
// append response data to the data string every time
// we receive new data chunks in the response
req.on('data', (chunk) => { data += chunk })
// Once the response is finished, log the entire data
// that we received
req.on('end', () => {
console.log(`\n${data}`)
session.close();
});
req.on('error', (error) => {
console.log(error);
});
req.end();
Please note that the actual hostname has been replaced with somedomain.com. Running this, results in data getting logged, as expected, however, the process doesn't shut down gracefully. I get the following unhandled error in the terminal.
node:events:504
throw er; // Unhandled 'error' event
^
Error [ERR_HTTP2_STREAM_ERROR]: Stream closed with error code NGHTTP2_FLOW_CONTROL_ERROR
at new NodeError (node:internal/errors:371:5)
at ClientHttp2Stream._destroy (node:internal/http2/core:2330:13)
at _destroy (node:internal/streams/destroy:102:25)
at ClientHttp2Stream.destroy (node:internal/streams/destroy:64:5)
at Http2Stream.onStreamClose (node:internal/http2/core:544:12)
Emitted 'error' event on ClientHttp2Stream instance at:
at emitErrorNT (node:internal/streams/destroy:157:8)
at emitErrorCloseNT (node:internal/streams/destroy:122:3)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
code: 'ERR_HTTP2_STREAM_ERROR'
}
I understand it is possible that the server is behaving incorrectly. However, there should be a way on the nodejs client to close the session gracefully. Regardless, what would be the ideal way to handle such errors? I've already tried listening to session.on('error') and req.on('error') but that doesn't work.

Using setInterval with socket.write

This is the code that works but it writes the data just once:
var net = require('net');
var PORT = 3000;
var client = new net.Socket();
client.connect(PORT, function(){
client.write('{printing}');
})
I am looking to write the same thing every few seconds. Wrote the below code but it doesn't seem to work:
client.connect(PORT, function(){
setInterval(function(){
client.write('{ printing }');
},10000);
})
Following is the error that I keep getting:
node:events:355
throw er; // Unhandled 'error' event
^
Error: write EPIPE
at afterWriteDispatched (node:internal/stream_base_commons:160:15)
at writeGeneric (node:internal/stream_base_commons:151:3)
at Socket._writeGeneric (node:net:773:11)
at Socket._write (node:net:785:8)
at writeOrBuffer (node:internal/streams/writable:395:12)
at Socket.Writable.write (node:internal/streams/writable:340:10)
at Timeout._onTimeout (/app/src/index.js:135:14)
at listOnTimeout (node:internal/timers:557:17)
at processTimers (node:internal/timers:500:7)
Emitted 'error' event on Socket instance at:
at emitErrorNT (node:internal/streams/destroy:188:8)
at emitErrorCloseNT (node:internal/streams/destroy:153:3)
at processTicksAndRejections (node:internal/process/task_queues:81:21) {
errno: -32,
code: 'EPIPE',
syscall: 'write'
}
[nodemon] app crashed - waiting for file changes before starting..
This is how I fixed it:
client.connect(PORT, function(){
client.write('printing')
})
//adding drain if the buffer gets full
client.on('drain',()=>{
console.log("draining the buffer")
setTimeout(() => {
client.write('printing')
})
//reading the response recieved : ("ok")
client.on('data', (data) => {})
//in case of an error, closing the connection
client.on('error',err => {}).on('close',() => {
setTimeout(() => {
client.connect(PORT, function(){
client.write('printing')
})
},40000)
})
In this context, the EPIPE error probably means that you're trying to write to a socket that has been closed. Since the setInterval() example you show keeps going forever, that probably means that the socket you originally connected gets closed at some point, but your setInterval() is still firing and trying to write to it.
You don't show the overall context of what you're trying to accomplish here to know exactly what to suggest, but at a minimum, you need to call clearInterval() to stop the timer whenever the socket it's trying to write to gets closed, either on purpose or because of error.
Here's an example for how you could debug if this is what is happening to you:
const net = require('net');
const PORT = 3000;
const client = new net.Socket();
let timer;
function disableTimer() {
if (timer) {
clearInterval(timer);
timer = null;
}
}
client.on('error', err => {
console.log("socket error", err);
disableTimer();
}).on('close', () => {
console.log("socket closed");
disableTimer();
});
client.connect(PORT, function(){
timer = setInterval(function(){
client.write('{ printing }');
},10000);
});

Retry connection postgres Nodejs

I am using a postgres database for my express web server.
I am using the 'pg' library to execute queries on this database.
Here is my connection method :
const db = new Client({
user: 'xxx',
host: 'xxx',
database: 'xxx',
password: 'xxx',
port: xxx,
})
db.connect(err => {
if (err) {
console.error('connection error', err.stack)
} else {
console.log('connected')
}
Then to execute a request I do this:
db.query(MY_REQUEST, function (err, data) {
if (err) throw err;
res.render('hello/world', {
title: 'Hello',
data: data.rows
});
});`
It all works perfectly. But after several minutes without using my website, my connection to the db times out, and I get the following error:
node:events:355
throw er; // Unhandled 'error' event
^
Error: Connection terminated unexpectedly
at Connection.<anonymous> (/usr/src/app/node_modules/pg/lib/client.js:132:73)
at Object.onceWrapper (node:events:484:28)
at Connection.emit (node:events:378:20)
at Socket.<anonymous> (/usr/src/app/node_modules/pg/lib/connection.js:58:12)
at Socket.emit (node:events:378:20)
at TCP.<anonymous> (node:net:665:12)
Emitted 'error' event on Client instance at:
at Client._handleErrorEvent (/usr/src/app/node_modules/pg/lib/client.js:319:10)
at Connection.<anonymous> (/usr/src/app/node_modules/pg/lib/client.js:149:16)
at Object.onceWrapper (node:events:484:28)
[... lines matching original stack trace ...]
at TCP.<anonymous> (node:net:665:12)
How could I do to reconnect automatically when the connection is cut or when a request fails?
You should attach an error-handler in order to prevent the unhandled error crashing your app. It's as simple as:
db.on('error', e => {
console.error('DB error', e);
});
As to why the error happens we need more details, looks like it could be a connection reset due to idle-timeout?
You can create a function to control if you're connected to database or not, before you continue with your main function.
Create a function for controlling database connection status, reconnecting etc. and before you run a database related function, first start that middle function and wait for result, after that you can continue using database again.
If you want(which should be prefered way mostly), create that middle function as an async function and return a promise, when using that function wait for that function.

ECONNREFUSED in Node http module

When a remote site is off-line I am getting this error in my consuming client (Node.js v0.12.0 with the http module):
Uncaught exception: connect ECONNREFUSED
Error: connect ECONNREFUSED
at exports._errnoException (util.js:746:11)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:983:19)
The code I'm currently using looks like this:
var req = http.request(options, function (res) {
res.on('socket', function (socket) {
socket.setKeepAlive(true, 0);
socket.setNoDelay(true);
});
res.on('end', function () {
log.debug('Success');
}).on('error', function () {
log.error('Response parsing failed');
});
}).on('error', function () {
log.error('HTTP request failed');
});
req.write(packet);
req.end();
The "error" event is never fired when the ECONNREFUSED occurs, I've tried using the "clientError" event but this is not fired either.
How can I capture this error?
Extracted from: https://stackoverflow.com/a/4328705/4478897
NOTE: This post is a bit old
The next example is with the http.createClient but i think it could be the same
Unfortunately, at the moment there's no way to catch these exceptions directly, since all the stuff happens asynchronously in the background.
All you can do is to catch the uncaughtException's on your own:
process.on('uncaughtException', function (err) {
console.log(err);
});
Maybe that helps you!
More this: https://stackoverflow.com/a/19793797/4478897
UPDATE:
did you tried to change log.error() to console.error() ???

socket hanging and node crashing

I have a node app that posts data to remote apis and fetches the responses. It works fine but at times the node server crashes and generates the following errror:
events.js:71
throw arguments[1]; // Unhandled 'error' event
^
Error: socket hang up
at createHangUpError (http.js:1264:15)
at Socket.socketCloseListener (http.js:1315:23)
at Socket.EventEmitter.emit (events.js:126:20)
at Socket._destroy.destroyed (net.js:358:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
I googled and found that it happens due to some timeout thing but i am not really sure as to how to overcome this.
Here is the required code in my server.js:
if(request.body.company=="CQ")
{
var postData={firstName:request.body.firstname,lastName:request.body.lastname,Email:request.body.email,DayPhoneNumber:request.body.daytimePhone,Address1:request.body.addressOne,city:request.body.city,state:request.body.State,postalCode:request.body.zip,AreaOfIntrest:request.body.areaOfInterest,VendorLocationId:"38404",Notes:request.body.Notes,GraduationYear:request.body.graduationYear,AffiliateLocationId:"12345",LocationId:"12345",CampaignId:"12345"};
var options={hostname:'webservices.someapi.com', path:'/ILM/Default.ashx?'+qs.stringify(postData), method:'GET'};
var req = http.request(options, function(res) {
res.on('data', function (chunk) {
edModel.find({$and:[{daytimePhone:request.body.daytimePhone},{company:"CQ"}]},function(err,count){
if(count.length==0)
{
var sr='RESPONSE: ' + chunk;
if(sr.indexOf('status="Error"')==-1)
{
request.body.leadid=sr;
var sr=sr.slice(sr.indexOf("leadid"));
sr=sr.slice(0,sr.indexOf(">"));
edDoc=new edModel(request.body);
edDoc.save();
response.send({response:sr});
}
else
{
response.send({response:sr});
}
}
else
{
response.send({response:"<span style='color:red'>Duplicate Lead.<br> A lead with this number already exists in our database</span>"});
}
});
});
});
// write data to request body
req.write('data\n');
req.end();
}
I have several such if else conditions in the server.js file.
in node 0.8.20 there was a bug about that problem. try using http.get instead of http.request. or just dont use 0.8.20 if you use that version.

Resources