Skip to content

Commit f43b216

Browse files
Prevented connection pool from triggering a runtime exception when stream_select is interrupted by a signal.
1 parent 35b8798 commit f43b216

File tree

2 files changed

+47
-16
lines changed

2 files changed

+47
-16
lines changed

src/Connection/StreamSocketConnectionPool.php

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,29 @@ public function operate(ConnectionHandlerFactoryInterface $connectionHandlerFact
5959
$read = array_merge(['pool' => $this->serverSocket], $this->clientSockets);
6060

6161
if (false === @stream_select($read, $write, $except, $timeoutLoopSeconds, $timeoutLoopMicroseconds)) {
62-
throw new \RuntimeException('stream_select failed');
63-
}
62+
$error = error_get_last();
6463

65-
foreach (array_keys($read) as $id) {
66-
if ('pool' === $id) {
67-
$this->acceptConnection($connectionHandlerFactory);
68-
} else {
69-
$this->connectionHandlers[$id]->ready();
64+
if (false === stripos($error['message'], 'interrupted system call')) {
65+
throw new \RuntimeException('stream_select failed: '.$error['message']);
66+
}
67+
} else {
68+
foreach (array_keys($read) as $id) {
69+
if ('pool' === $id) {
70+
$this->acceptConnection($connectionHandlerFactory);
71+
} else {
72+
$this->connectionHandlers[$id]->ready();
73+
}
7074
}
71-
}
7275

73-
$this->removeConnections();
76+
$this->removeConnections();
77+
}
7478
}
7579

7680
/**
7781
* {@inheritdoc}
7882
*/
7983
public function shutdown()
8084
{
81-
$this->acceptingNewConnections = false;
82-
8385
foreach ($this->connectionHandlers as $connectionHandler) {
8486
$connectionHandler->shutdown();
8587
}
@@ -99,6 +101,8 @@ public function shutdown()
99101

100102
$this->removeConnections();
101103
}
104+
105+
fclose($this->serverSocket);
102106
}
103107

104108
/**

test/Connection/StreamSocketConnectionPoolTest.php

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,30 @@ public function testStreamSelectFail()
7979
$connectionPool->operate($connectionHandlerFactory, 1);
8080
}
8181

82+
/**
83+
* Test stream_select signal interrupt doesn't trigger \RunTime exception
84+
*/
85+
public function testStreamSelectSignalInterrupt()
86+
{
87+
$address = 'tcp://localhost:7000';
88+
$serverSocket = stream_socket_server($address);
89+
$connectionPool = new StreamSocketConnectionPool($serverSocket);
90+
91+
$connectionHandlerFactory = new CallableConnectionHandlerFactory(function () {});
92+
93+
$alarmCalled = false;
94+
95+
pcntl_signal(SIGALRM, function () use (&$alarmCalled) {
96+
$alarmCalled = true;
97+
});
98+
99+
pcntl_alarm(1);
100+
101+
$connectionPool->operate($connectionHandlerFactory, 1);
102+
103+
$this->assertTrue($alarmCalled);
104+
}
105+
82106
/**
83107
* Test shutdown.
84108
*/
@@ -94,13 +118,14 @@ public function testShutdown()
94118
$connection = new StreamSocketConnection($clientSocket);
95119
$connection->write('hello');
96120

97-
$shutdown = false;
121+
$shutdownCalled = false;
122+
$readCalled = false;
98123

99-
$connectionHandlerCallback = function ($method, ConnectionInterface $connection) use (&$shutdown) {
124+
$connectionHandlerCallback = function ($method, ConnectionInterface $connection) use (&$shutdownCalled, &$readCalled) {
100125
if ('shutdown' === $method) {
101-
$shutdown = true;
126+
$shutdownCalled = true;
102127
} elseif ('ready' === $method) {
103-
// Do not close immediately, close on read
128+
$readCalled = true;
104129
$connection->close();
105130
}
106131
};
@@ -112,6 +137,8 @@ public function testShutdown()
112137
// Shutdown connection pool
113138
$connectionPool->shutdown();
114139

115-
$this->assertTrue($shutdown);
140+
// Make sure the handler cleaned up properly and got a chance to read the data
141+
$this->assertTrue($shutdownCalled);
142+
$this->assertTrue($readCalled);
116143
}
117144
}

0 commit comments

Comments
 (0)