2012-01-01 13 views
5

Estoy jugando con el nodo y (por el momento) simplemente tratando de transmitir algunos archivos desde el sistema de archivos a través de HTTP.Cómo cerrar limpiamente FD en la conexión HTTP abortada en node.js

La aplicación Apache Bench (ab) en mi máquina OS X Lion tiene errores y parece abortar las conexiones prematuramente. Esto parece haber resaltado un problema con mi aplicación node.js donde filtra manejadores de archivo si la conexión se cancela.

He reducido esto a un caso de prueba node.js simple. Cuando inicio esta y corro 'ab' en contra de ella, al final me consigo una excepción EMFILE debido a demasiados identificadores de archivo abierto:

// app.js 

var count = 0; 
require('http').createServer(function(req,res){ 

    console.log('request ' + ++count); 

    res.writeHead(200); 
    require('fs').createReadStream(
     '/Users/tom/files/8339cdf73594d8f0aab87da123e9e0380723b471' 
    ).pipe(res); 

}).listen('3000'); 


$ node app.js 
request 1 
... 
request 317 
request 318 
request 319 

stream.js:105 
     throw er; // Unhandled stream error in pipe. 
      ^
Error: EMFILE, too many open files '/Users/tom/files/8339cdf73594d8f0aab87da123e9e0380723b471' 

asumo lo que está sucediendo es la conexión HTTP concluye, pero .pipe del nodo() mecanismo no sabe dejar de leer de la secuencia legible y cerrar el FD, así que traté de manejar el evento 'cerrar' en el HTTP ServerRequest y destruir el FD, pero algo parece estar leyendo de él ya que me da un mal error FD (EBADF) en su lugar:

// app.js 

var count = 0; 
require('http').createServer(function(req,res){ 

    console.log('request ' + ++count); 

    res.writeHead(200); 
    var file = require('fs').createReadStream(
     '/Users/tom/dev/cloudstore2/files/8339cdf73594d8f0aab87da123e9e0380723b471' 
    ); 

    req.on('close', function(){ 
     console.log('request received close - destroying read FD'); 
     file.destroy(); 
    }); 

    file.pipe(res); 

}).listen('3000'); 

$ node app.js 
... 
request 112 
request 113 
request received close - destroying read FD 
request received close - destroying read FD 
request received close - destroying read FD 
request received close - destroying read FD 
request received close - destroying read FD 
request received close - destroying read FD 
request received close - destroying read FD 

events.js:48 
     throw arguments[1]; // Unhandled 'error' event 
        ^
Error: EBADF, bad file descriptor 

¿hay una manera 'correcta' para manejar estas conexiones HTTP abortados y cerrar mi F relacionados leen corriente, o aM ¿Veo un error en el manejo de node.js '.pipe()?


Actualización: Al detectar el evento 'error' en mi lector de archivos, que pueden evitar la aplicación de morir durante este proceso, pero es que la forma correcta de hacer esto? Siento que me falta algo para evitar lanzar un error FD malo en primer lugar.

<snip> 
    var file = require('fs').createReadStream(
     '/Users/tom/dev/cloudstore2/files/8339cdf73594d8f0aab87da123e9e0380723b471' 
    ); 

    file.on('error', function(err){ 
     console.log('error handled in file reader: ' + err); 
    }); 

    req.on('close', function(){ 
     console.log('request received close - destroying read FD'); 
     file.destroy(); 
    }); 

    file.pipe(res); 
</snip> 

Respuesta

2

Según la documentación nodejs

http.ServerRequest

Evento: 'cerca'

indica que la conexión subyacente se dio por terminado antes de Response.End() fue llamado o fue capaz de enjuagar.

Al igual que 'end', este evento se produce solo una vez por solicitud, y no se dispararán más eventos de 'datos' después.

Nota: 'cerrar' puede disparar después de 'final', pero no al revés.

Creo que end() mata el destino fh de su tubería, lo que significa que si se dispara primero hay una pequeña ventana donde la tubería podría estar intentando escribir a la solicitud fh después de que está cerrada. Intenta poner tu llamada file.destroy() en el evento end().

Traté de probar mi idea, pero no puedo obtener el error así que por favor avíseme si eso funcionó para usted. Me preocupa que me encuentre con este problema cuando abro mi aplicación a otros usuarios.

+0

Esto es correcto, pero no estaba disponible cuando presenté esta pregunta. :) Archivé el Nodo número 2453 (https://github.com/joyent/node/issues/2453) y se agregó el evento 'cerrar'. – dec

Cuestiones relacionadas