1919
2020use MongoDB \BSON \Serializable ;
2121use MongoDB \Driver \Cursor ;
22- use MongoDB \Driver \Exception \ConnectionTimeoutException ;
22+ use MongoDB \Driver \Exception \ConnectionException ;
2323use MongoDB \Driver \Exception \RuntimeException ;
24+ use MongoDB \Driver \Exception \ServerException ;
2425use MongoDB \Exception \InvalidArgumentException ;
2526use MongoDB \Exception \ResumeTokenException ;
2627use IteratorIterator ;
3536 */
3637class 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