PHP + Fcgid se bloquea si se interrumpe la descarga

PHP + Fcgid se bloquea si se interrumpe la descarga

Nota:Administradores, voten por la migración a ServerFault.

Estoy usando una configuración LAMP con PHP ejecutándose mod_fcgid. Para la mayoría de las solicitudes, esto funciona bien, pero he notado que cuando descargo un archivo pero interrumpo la descarga antes de que se complete, el proceso php-cgi que estaba entregando el archivo bloquea el intento de escribir más datos hasta que se alcanza IPCCommTimeout. Una vez que se alcanza el tiempo de espera, el proceso se interrumpe y comienza a atender otras solicitudes nuevamente.

¿Hay alguna configuración disponible para fcgid que pueda configurar para que se cancele si no hay nada que capture la salida? ¿Hay algo que pueda hacer en PHP para manejarlo?

El problema no ocurre si no se interrumpe la descarga; de hecho, sólo lo noté porque estaba intentando transmitir un archivo FLV usando gddflvplayer, que parece enviar una breve solicitud para obtener los primeros fotogramas, luego otra para reproducirlo, y esto causa el mismo problema.

Para su información, este es el rastro del proceso cgi colgante; permanece así hasta que finalmente es interrumpido, presumiblemente por el administrador de procesos cuando se IPCCommTimeoutalcanza. Supongo que se bloquea al intentar mostrar los resultados de la readfile()llamada, pero Apache ya no está escuchando (ya que el usuario canceló la solicitud).

root@some-machine:~# strace -p 24837
Process 24837 attached - interrupt to quit
write(3, "\5|A\313%\35\337\376\275\237\230\266\242\371\37YjzD<\322\215\357\336:M\362P\335\242\214\341"..., 17432

Los registros indican que la solicitud finalmente se cosecha debido al tiempo de espera.

mod_fcgid: read data timeout in 240 seconds

El código de descarga se utiliza más o menos readfilepara entregar el archivo, con algunos encabezados involucrados también (nota: en este código, Headeres más o menos solo un contenedor header()para evitar problemas en las pruebas).

$filepath    = '/some/path/foo.flv';
$filename    = 'foo.flv';
$disposition = 'inline';

$h = Header::get();
$h->send('Pragma: public');
$h->send('Content-Transfer-Encoding: binary');
$h->send('Content-type: ' . FileSystem::get()->getMimeType($filepath));
$h->send('Content-Length: ' . FileSystem::get()->getFileSize($filepath));
$h->send('Content-Disposition: ' . $disposition . '; filename="' . $filename . '"');
$h->send('Content-transfer-encoding: 8bit');
$h->send('Expires: 0');
$h->send('Pragma: cache');
$h->send('Cache-Control: private');

flush();
readfile($filepath);

información relacionada