Skip to content

Commit adce1eb

Browse files
committed
added reconfigurable timeouts on a streamsocket
1 parent c1173ef commit adce1eb

File tree

4 files changed

+77
-6
lines changed

4 files changed

+77
-6
lines changed

src/connection/AConnection.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,9 @@ public function getTimeout(): float
7171
{
7272
return $this->timeout;
7373
}
74+
75+
public function setTimeout(float $timeout): void
76+
{
77+
$this->timeout = $timeout;
78+
}
7479
}

src/connection/IConnection.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@ public function getIp(): string;
3131
public function getPort(): int;
3232

3333
public function getTimeout(): float;
34+
35+
public function setTimeout(float $timeout): void;
3436
}

src/connection/StreamSocket.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
use Bolt\Bolt;
77
use Bolt\error\ConnectException;
8+
use function floor;
9+
use function stream_set_timeout;
810

911
/**
1012
* Stream socket class
@@ -66,10 +68,7 @@ public function connect(): bool
6668
}
6769
}
6870

69-
$timeout = (int) floor($this->timeout);
70-
if (!stream_set_timeout($this->stream, $timeout, (int) floor(($this->timeout - $timeout) * 1000000))) {
71-
throw new ConnectException('Cannot set timeout on stream');
72-
}
71+
$this->setTimeoutOnStream();
7372

7473
return true;
7574
}
@@ -120,4 +119,21 @@ public function disconnect()
120119
stream_socket_shutdown($this->stream, STREAM_SHUT_RDWR);
121120
}
122121

122+
public function setTimeout(float $timeout): void
123+
{
124+
parent::setTimeout($timeout);
125+
$this->setTimeoutOnStream();
126+
}
127+
128+
/**
129+
* @return void
130+
* @throws ConnectException
131+
*/
132+
private function setTimeoutOnStream(): void
133+
{
134+
$timeout = (int)floor($this->timeout);
135+
if (!stream_set_timeout($this->stream, $timeout, (int)floor(($this->timeout - $timeout) * 1000000))) {
136+
throw new ConnectException('Cannot set timeout on stream');
137+
}
138+
}
123139
}

tests/connection/StreamSocketTest.php

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
use Bolt\Bolt;
66
use Bolt\connection\StreamSocket;
77
use Bolt\error\ConnectException;
8+
use Bolt\error\MessageException;
9+
use Bolt\helpers\Auth;
10+
use Bolt\protocol\V4;
811
use Exception;
912
use PHPUnit\Framework\TestCase;
13+
use function microtime;
1014

1115
final class StreamSocketTest extends TestCase
1216
{
@@ -18,7 +22,7 @@ public function testMillisecondTimeout(): void
1822
$socket = new StreamSocket($GLOBALS['NEO_HOST'] ?? '127.0.0.1', (int) ($GLOBALS['NEO_PORT'] ?? 7687), 1.5);
1923
$bolt = new Bolt($socket);
2024
$protocol = $bolt->build();
21-
$protocol->init(\Bolt\helpers\Auth::basic($GLOBALS['NEO_USER'], $GLOBALS['NEO_PASS']));
25+
$protocol->init(Auth::basic($GLOBALS['NEO_USER'], $GLOBALS['NEO_PASS']));
2226

2327
$time = microtime(true);
2428
try {
@@ -42,7 +46,7 @@ public function testSecondsTimeout(): void
4246
$socket = new StreamSocket($GLOBALS['NEO_HOST'] ?? '127.0.0.1', (int) ($GLOBALS['NEO_PORT'] ?? 7687), 1);
4347
$bolt = new Bolt($socket);
4448
$protocol = $bolt->build();
45-
$protocol->init(\Bolt\helpers\Auth::basic($GLOBALS['NEO_USER'], $GLOBALS['NEO_PASS']));
49+
$protocol->init(Auth::basic($GLOBALS['NEO_USER'], $GLOBALS['NEO_PASS']));
4650

4751
$time = microtime(true);
4852
try {
@@ -56,4 +60,48 @@ public function testSecondsTimeout(): void
5660
$this->assertEqualsWithDelta(1.0, $newTime - $time, 0.2);
5761
}
5862
}
63+
64+
public function testTimeoutRecoverAndReset(): void
65+
{
66+
$streamSocket = new StreamSocket($GLOBALS['NEO_HOST'] ?? '127.0.0.1', (int) ($GLOBALS['NEO_PORT'] ?? 7687), 1);
67+
/** @var V4 $protocol */
68+
$protocol = (new Bolt($streamSocket))->build();
69+
$protocol->hello(Auth::basic($GLOBALS['NEO_USER'], $GLOBALS['NEO_PASS']));
70+
71+
$time = microtime(true);
72+
try {
73+
$protocol->run('FOREACH ( i IN range(1,10000) |
74+
MERGE (d:Day {day: i})
75+
)');
76+
$this->fail('No timeout error triggered');
77+
} catch (ConnectException $e) {
78+
$newTime = microtime(true);
79+
80+
$this->assertEqualsWithDelta(1.0, $newTime - $time, 0.2);
81+
}
82+
83+
$streamSocket->setTimeout(100.0);
84+
try {
85+
$protocol->reset();
86+
} catch (MessageException $e) {
87+
echo $e->getMessage();
88+
$protocol = (new Bolt($streamSocket))->build();
89+
$protocol->hello(Auth::basic($GLOBALS['NEO_USER'], $GLOBALS['NEO_PASS']));
90+
}
91+
$this->assertTrue(true);
92+
93+
$streamSocket->setTimeout(1.0);
94+
95+
$time = microtime(true);
96+
try {
97+
$protocol->run('FOREACH ( i IN range(1,10000) |
98+
MERGE (d:Day {day: i})
99+
)');
100+
$this->fail('No timeout error triggered');
101+
} catch (ConnectException $e) {
102+
$newTime = microtime(true);
103+
104+
$this->assertEqualsWithDelta(1.0, $newTime - $time, 0.2);
105+
}
106+
}
59107
}

0 commit comments

Comments
 (0)