Skip to content

Commit 2a288a0

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 e621613 commit 2a288a0

File tree

1 file changed

+40
-27
lines changed

1 file changed

+40
-27
lines changed

src/ChangeStream.php

Lines changed: 40 additions & 27 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;
122+
if ($this->isResumableError($e)) {
123+
$this->resume();
116124
}
117-
if ($e->getCode() === self::CURSOR_NOT_FOUND) {
118-
$resumable = true;
119-
}
120-
if ($e instanceof ConnectionTimeoutException) {
121-
$resumable = true;
122-
}
123-
}
124-
if ($resumable) {
125-
$this->resume();
126125
}
127126
}
128127

@@ -132,7 +131,6 @@ public function next()
132131
*/
133132
public function rewind()
134133
{
135-
$resumable = false;
136134
try {
137135
$this->csIt->rewind();
138136
if ($this->valid()) {
@@ -144,18 +142,9 @@ public function rewind()
144142
$this->resumeCallable = null;
145143
}
146144
} catch (RuntimeException $e) {
147-
if (strpos($e->getMessage(), "not master") !== false) {
148-
$resumable = true;
145+
if ($this->isResumableError($e)) {
146+
$this->resume();
149147
}
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();
159148
}
160149
}
161150

@@ -201,6 +190,30 @@ private function extractResumeToken($document)
201190
return $resumeToken;
202191
}
203192

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

0 commit comments

Comments
 (0)