zeromq/php-zmq

PHP/HTTPD processes are stuck in a closing connection state after sending messages via zmq push

MkFoster opened this issue · 1 comments

After executing a large number of ZMQ::SOCKET_PUSH operations, PHP child processes running under Apache HTTPD get stuck in "closing connection" state. This will create a blocking condition once all the PHP/HTTPD child processes are stuck in a closing connection state and kill the app. Note, that this only happens if there is no process pulling the messages. (I.e. a daemon intended to pull the messages has failed). If there is something pulling messages off at the other end, all is well and the processes do not appear to get stuck.

To replicate, set MaxRequestsPerChild to a low number in the httpd.conf (I.e. 5) and hit a PHP page running the code below with a large number of requests using JMeter or some other load test tool. A couple thousand requests should do it. Use Apache mod_status and observe that after the load is removed, the PHP child processes enter the "C" Closing connection state and never leave (or least for the 20 minutes I bothered to watch). See the sample code below.

This is killing us when our logger daemon fails so any guidance is appreciated. We would prefer to lose the log messages and keep going. Thanks!

Environment:
Apache/2.2.15 on Scientific Linux 6.5
PHP Version 5.5.16 with the zmq extension loaded
libzmq version 4.1.4

Sample code:
`<?php

$dsn = 'tcp://127.0.0.1:50001';
$zmq = new ZMQContext(1, true);
$socket = $zmq->getSocket(ZMQ::SOCKET_PUSH, 'logs');
$socket->connect($dsn);
$mypid = getmypid();
$message = $mypid . ' Some message';
$socket->send($message, ZMQ::MODE_DONTWAIT);
echo $mypid;`

apache_server_status

After scanning the PHP/ZMQ docs some more I found a "fix" for this by simply setting the socket send and linger timeout options to a short duration (I.e. 2 seconds). PHP/HTTPD child processes now close quickly.

`<?php

$dsn = 'tcp://127.0.0.1:50001';
$zmq = new ZMQContext(1, true);
$socket = $zmq->getSocket(ZMQ::SOCKET_PUSH, 'logs');
$socket->setSockOpt(\ZMQ::SOCKOPT_SNDTIMEO, 2000);
$socket->setSockOpt(\ZMQ::SOCKOPT_RCVTIMEO, 2000);
$socket->setSockOpt(\ZMQ::SOCKOPT_LINGER, 2000);
$socket->connect($dsn);
$mypid = getmypid();
$message = $mypid . ' Some message';
$socket->send($message, ZMQ::MODE_DONTWAIT);
echo $mypid;`