Duplicate EPIPE Errors #5851
Comments
Nice find! If you change the
The first error is from the stream.Writable class, and then it re-emits on the net.Socket object. I think this is a bug. |
Cool! Which |
@skeggse I think the Stream one is better, since it happens first. It'd be important to make sure we're not losing any error events by removing the emit from net.js, but I'm pretty sure that every write error will end up getting raised in _stream_writable.js. Patch (with a test!) welcome. |
I was bugged by this very issue for couple hours now just to find out it's been reporter. Have the same escalation of the error.
@isaacs, what's the best way to handle such scenario considering that I should catch only one of the errors? I would prefer to be able to catch |
Also bit by this today. Spent couple of hours digging in the node source code and found that 'error' event is emitted both in net.js and _stream_writable.js so I guess EPIPE is just one case for duplicate 'error' event. @isaacs Also found that _destroy() is not completely reentrance-safe, causing server connection count wrong. See comments below. Socket.prototype._destroy = function(exception, cb) {
debug('destroy');
var self = this;
function fireErrorCallbacks() {
// cb() can call into onwrite() in _stream_writable.js emitting an error,
// which can be handled in socketErrorListener() in http.js and calls destroy() again
if (cb) cb(exception);
if (exception && !self.errorEmitted) {
process.nextTick(function() {
self.emit('error', exception);
});
self.errorEmitted = true;
}
};
if (this.destroyed) { // when the above case happens, this is not set yet
debug('already destroyed, fire error callbacks');
fireErrorCallbacks();
return;
}
self._connecting = false;
this.readable = this.writable = false;
timers.unenroll(this);
debug('close');
if (this._handle) {
if (this !== process.stderr)
debug('close handle');
var isException = exception ? true : false;
this._handle.close(function() {
debug('emit close');
self.emit('close', isException);
});
this._handle.onread = noop;
this._handle = null;
}
fireErrorCallbacks();
this.destroyed = true; // it's set after fireErrorCallbacks();
if (this.server) {
COUNTER_NET_SERVER_CONNECTION_CLOSE(this);
debug('has server');
this.server._connections--;
if (this.server._emitCloseIfDrained) {
this.server._emitCloseIfDrained();
}
}
}; |
I'm
spawn
ing a process usingchild_process
. I assume that at some point the child process will fail for whatever reason, so I need to be listening for all applicableerror
events, to avoid the entire process shutting down thanks to theEventEmitter
throwing the uncaughterror
event.For some odd reason, I get two
EPIPE
errors with the following code.That'd be fine, except that I want to remove the old
child
andspawn
a new one. To avoid handling events for an ostensibly dead process, IremoveAllListeners
for thechild
and its stdio. Then, when the secondEPIPE
error hits, the application fails. I could, of course,removeAllListeners
, then add noop listeners for the error events, but that's more of a workaround.Is this expected behavior, and if so, why?
The text was updated successfully, but these errors were encountered: