Skip to content

Commit 66b4a91

Browse files
committed
PHPLIB-351: Update logic for identifying resumable errors
Skip redundant error message checks, since their codes do not overlap with the three errors specifically excluded by the spec and all other server errors are resumable. Deprecate the unused class constant, which can be removed in 2.0 (PHPLIB-360).
1 parent 98dbb01 commit 66b4a91

File tree

1 file changed

+40
-26
lines changed

1 file changed

+40
-26
lines changed

src/ChangeStream.php

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919

2020
use MongoDB\BSON\Serializable;
2121
use MongoDB\Driver\Cursor;
22-
use MongoDB\Driver\Exception\ConnectionTimeoutException;
22+
use MongoDB\Driver\Exception\ConnectionException;
2323
use MongoDB\Driver\Exception\RuntimeException;
24+
use MongoDB\Driver\Exception\ServerException;
2425
use MongoDB\Exception\InvalidArgumentException;
2526
use MongoDB\Exception\ResumeTokenException;
2627
use IteratorIterator;
@@ -35,14 +36,22 @@
3536
*/
3637
class ChangeStream implements Iterator
3738
{
39+
/**
40+
* @deprecated 1.4
41+
* @todo Remove this in 2.0 (see: PHPLIB-360)
42+
*/
43+
const CURSOR_NOT_FOUND = 43;
44+
45+
private static $errorCodeCappedPositionLost = 136;
46+
private static $errorCodeInterrupted = 11601;
47+
private static $errorCodeCursorKilled = 237;
48+
3849
private $resumeToken;
3950
private $resumeCallable;
4051
private $csIt;
4152
private $key = 0;
4253
private $hasAdvanced = false;
4354

44-
const CURSOR_NOT_FOUND = 43;
45-
4655
/**
4756
* Constructor.
4857
*
@@ -91,7 +100,6 @@ public function key()
91100
*/
92101
public function next()
93102
{
94-
$resumable = false;
95103
try {
96104
$this->csIt->next();
97105
if ($this->valid()) {
@@ -111,18 +119,9 @@ public function next()
111119
$this->resumeCallable = null;
112120
}
113121
} catch (RuntimeException $e) {
114-
if (strpos($e->getMessage(), "not master") !== false) {
115-
$resumable = true;
116-
}
117-
if ($e->getCode() === self::CURSOR_NOT_FOUND) {
118-
$resumable = true;
122+
if ($this->isResumableError($e)) {
123+
$this->resume();
119124
}
120-
if ($e instanceof ConnectionTimeoutException) {
121-
$resumable = true;
122-
}
123-
}
124-
if ($resumable) {
125-
$this->resume();
126125
}
127126
}
128127

@@ -144,18 +143,9 @@ public function rewind()
144143
$this->resumeCallable = null;
145144
}
146145
} catch (RuntimeException $e) {
147-
if (strpos($e->getMessage(), "not master") !== false) {
148-
$resumable = true;
146+
if ($this->isResumableError($e)) {
147+
$this->resume();
149148
}
150-
if ($e->getCode() === self::CURSOR_NOT_FOUND) {
151-
$resumable = true;
152-
}
153-
if ($e instanceof ConnectionTimeoutException) {
154-
$resumable = true;
155-
}
156-
}
157-
if ($resumable) {
158-
$this->resume();
159149
}
160150
}
161151

@@ -201,6 +191,30 @@ private function extractResumeToken($document)
201191
return $resumeToken;
202192
}
203193

194+
/**
195+
* Determines if an exception is a resumable error.
196+
*
197+
* @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#resumable-error
198+
* @param RuntimeException $exception
199+
* @return boolean
200+
*/
201+
private function isResumableError(RuntimeException $exception)
202+
{
203+
if ($exception instanceof ConnectionException) {
204+
return true;
205+
}
206+
207+
if ( ! $exception instanceof ServerException) {
208+
return false;
209+
}
210+
211+
if (in_array($exception->getCode(), [self::$errorCodeCappedPositionLost, self::$errorCodeCursorKilled, self::$errorCodeInterrupted])) {
212+
return false;
213+
}
214+
215+
return true;
216+
}
217+
204218
/**
205219
* Creates a new changeStream after a resumable server error.
206220
*

0 commit comments

Comments
 (0)