@@ -22,7 +22,7 @@ import NodeChannel from './ch-node';
22
22
import { Chunker , Dechunker } from './chunking' ;
23
23
import packStreamUtil from './packstream-util' ;
24
24
import { alloc } from './buf' ;
25
- import { newError } from './../error' ;
25
+ import { newError , PROTOCOL_ERROR } from './../error' ;
26
26
import ChannelConfig from './ch-config' ;
27
27
import urlUtil from './url-util' ;
28
28
import StreamObserver from './stream-observer' ;
@@ -120,7 +120,7 @@ class Connection {
120
120
this . _packer = packStreamUtil . createLatestPacker ( this . _chunker ) ;
121
121
this . _unpacker = packStreamUtil . createLatestUnpacker ( disableLosslessIntegers ) ;
122
122
123
- this . _isHandlingFailure = false ;
123
+ this . _ackFailureMuted = false ;
124
124
this . _currentFailure = null ;
125
125
126
126
this . _state = new ConnectionState ( this ) ;
@@ -241,25 +241,8 @@ class Connection {
241
241
this . _currentObserver . onError ( this . _currentFailure ) ;
242
242
} finally {
243
243
this . _updateCurrentObserver ( ) ;
244
- // Things are now broken. Pending observers will get FAILURE messages routed until
245
- // We are done handling this failure.
246
- if ( ! this . _isHandlingFailure ) {
247
- this . _isHandlingFailure = true ;
248
-
249
- // isHandlingFailure was false, meaning this is the first failure message
250
- // we see from this failure. We may see several others, one for each message
251
- // we had "optimistically" already sent after whatever it was that failed.
252
- // We only want to and need to ACK the first one, which is why we are tracking
253
- // this _isHandlingFailure thing.
254
- this . _ackFailure ( {
255
- onNext : NO_OP ,
256
- onError : NO_OP ,
257
- onCompleted : ( ) => {
258
- this . _isHandlingFailure = false ;
259
- this . _currentFailure = null ;
260
- }
261
- } ) ;
262
- }
244
+ // Things are now broken. Pending observers will get FAILURE messages routed until we are done handling this failure.
245
+ this . _ackFailureIfNeeded ( ) ;
263
246
}
264
247
break ;
265
248
case IGNORED :
@@ -268,7 +251,7 @@ class Connection {
268
251
if ( this . _currentFailure && this . _currentObserver . onError )
269
252
this . _currentObserver . onError ( this . _currentFailure ) ;
270
253
else if ( this . _currentObserver . onError )
271
- this . _currentObserver . onError ( payload ) ;
254
+ this . _currentObserver . onError ( newError ( 'Ignored either because of an error or RESET' ) ) ;
272
255
} finally {
273
256
this . _updateCurrentObserver ( ) ;
274
257
}
@@ -282,72 +265,116 @@ class Connection {
282
265
initialize ( clientName , token , observer ) {
283
266
log ( "C" , "INIT" , clientName , token ) ;
284
267
const initObserver = this . _state . wrap ( observer ) ;
285
- this . _queueObserver ( initObserver ) ;
286
- this . _packer . packStruct ( INIT , [ this . _packable ( clientName ) , this . _packable ( token ) ] ,
287
- ( err ) => this . _handleFatalError ( err ) ) ;
288
- this . _chunker . messageBoundary ( ) ;
289
- this . sync ( ) ;
268
+ const queued = this . _queueObserver ( initObserver ) ;
269
+ if ( queued ) {
270
+ this . _packer . packStruct ( INIT , [ this . _packable ( clientName ) , this . _packable ( token ) ] ,
271
+ ( err ) => this . _handleFatalError ( err ) ) ;
272
+ this . _chunker . messageBoundary ( ) ;
273
+ this . sync ( ) ;
274
+ }
290
275
}
291
276
292
277
/** Queue a RUN-message to be sent to the database */
293
278
run ( statement , params , observer ) {
294
279
log ( "C" , "RUN" , statement , params ) ;
295
- this . _queueObserver ( observer ) ;
296
- this . _packer . packStruct ( RUN , [ this . _packable ( statement ) , this . _packable ( params ) ] ,
297
- ( err ) => this . _handleFatalError ( err ) ) ;
298
- this . _chunker . messageBoundary ( ) ;
280
+ const queued = this . _queueObserver ( observer ) ;
281
+ if ( queued ) {
282
+ this . _packer . packStruct ( RUN , [ this . _packable ( statement ) , this . _packable ( params ) ] ,
283
+ ( err ) => this . _handleFatalError ( err ) ) ;
284
+ this . _chunker . messageBoundary ( ) ;
285
+ }
299
286
}
300
287
301
288
/** Queue a PULL_ALL-message to be sent to the database */
302
289
pullAll ( observer ) {
303
290
log ( "C" , "PULL_ALL" ) ;
304
- this . _queueObserver ( observer ) ;
305
- this . _packer . packStruct ( PULL_ALL , [ ] , ( err ) => this . _handleFatalError ( err ) ) ;
306
- this . _chunker . messageBoundary ( ) ;
291
+ const queued = this . _queueObserver ( observer ) ;
292
+ if ( queued ) {
293
+ this . _packer . packStruct ( PULL_ALL , [ ] , ( err ) => this . _handleFatalError ( err ) ) ;
294
+ this . _chunker . messageBoundary ( ) ;
295
+ }
307
296
}
308
297
309
298
/** Queue a DISCARD_ALL-message to be sent to the database */
310
299
discardAll ( observer ) {
311
300
log ( "C" , "DISCARD_ALL" ) ;
312
- this . _queueObserver ( observer ) ;
313
- this . _packer . packStruct ( DISCARD_ALL , [ ] , ( err ) => this . _handleFatalError ( err ) ) ;
314
- this . _chunker . messageBoundary ( ) ;
301
+ const queued = this . _queueObserver ( observer ) ;
302
+ if ( queued ) {
303
+ this . _packer . packStruct ( DISCARD_ALL , [ ] , ( err ) => this . _handleFatalError ( err ) ) ;
304
+ this . _chunker . messageBoundary ( ) ;
305
+ }
315
306
}
316
307
317
- /** Queue a RESET-message to be sent to the database. Mutes failure handling. */
318
- reset ( observer ) {
308
+ /**
309
+ * Send a RESET-message to the database. Mutes failure handling.
310
+ * Message is immediately flushed to the network. Separate {@link Connection#sync()} call is not required.
311
+ * @return {Promise<void> } promise resolved when SUCCESS-message response arrives, or failed when other response messages arrives.
312
+ */
313
+ resetAndFlush ( ) {
319
314
log ( 'C' , 'RESET' ) ;
320
- this . _isHandlingFailure = true ;
321
- let self = this ;
322
- let wrappedObs = {
323
- onNext : observer ? observer . onNext : NO_OP ,
324
- onError : observer ? observer . onError : NO_OP ,
325
- onCompleted : ( ) => {
326
- self . _isHandlingFailure = false ;
327
- if ( observer ) {
328
- observer . onCompleted ( ) ;
315
+ this . _ackFailureMuted = true ;
316
+
317
+ return new Promise ( ( resolve , reject ) => {
318
+ const observer = {
319
+ onNext : record => {
320
+ const neo4jError = this . _handleProtocolError ( 'Received RECORD as a response for RESET: ' + JSON . stringify ( record ) ) ;
321
+ reject ( neo4jError ) ;
322
+ } ,
323
+ onError : error => {
324
+ const neo4jError = this . _handleProtocolError ( 'Received FAILURE as a response for RESET: ' + error ) ;
325
+ reject ( neo4jError ) ;
326
+ } ,
327
+ onCompleted : ( ) => {
328
+ this . _ackFailureMuted = false ;
329
+ resolve ( ) ;
329
330
}
331
+ } ;
332
+ const queued = this . _queueObserver ( observer ) ;
333
+ if ( queued ) {
334
+ this . _packer . packStruct ( RESET , [ ] , err => this . _handleFatalError ( err ) ) ;
335
+ this . _chunker . messageBoundary ( ) ;
336
+ this . sync ( ) ;
330
337
}
331
- } ;
332
- this . _queueObserver ( wrappedObs ) ;
333
- this . _packer . packStruct ( RESET , [ ] , ( err ) => this . _handleFatalError ( err ) ) ;
334
- this . _chunker . messageBoundary ( ) ;
338
+ } ) ;
335
339
}
336
340
337
- /** Queue a ACK_FAILURE-message to be sent to the database */
338
- _ackFailure ( observer ) {
339
- log ( "C" , "ACK_FAILURE" ) ;
340
- this . _queueObserver ( observer ) ;
341
- this . _packer . packStruct ( ACK_FAILURE , [ ] , ( err ) => this . _handleFatalError ( err ) ) ;
342
- this . _chunker . messageBoundary ( ) ;
341
+ _ackFailureIfNeeded ( ) {
342
+ if ( this . _ackFailureMuted ) {
343
+ return ;
344
+ }
345
+
346
+ log ( 'C' , 'ACK_FAILURE' ) ;
347
+
348
+ const observer = {
349
+ onNext : record => {
350
+ this . _handleProtocolError ( 'Received RECORD as a response for ACK_FAILURE: ' + JSON . stringify ( record ) ) ;
351
+ } ,
352
+ onError : error => {
353
+ if ( ! this . _ackFailureMuted ) {
354
+ this . _handleProtocolError ( 'Received FAILURE as a response for ACK_FAILURE: ' + error ) ;
355
+ } else {
356
+ this . _currentFailure = null ;
357
+ }
358
+ } ,
359
+ onCompleted : ( ) => {
360
+ this . _currentFailure = null ;
361
+ }
362
+ } ;
363
+
364
+ const queued = this . _queueObserver ( observer ) ;
365
+ if ( queued ) {
366
+ this . _packer . packStruct ( ACK_FAILURE , [ ] , err => this . _handleFatalError ( err ) ) ;
367
+ this . _chunker . messageBoundary ( ) ;
368
+ this . sync ( ) ;
369
+ }
343
370
}
344
371
345
372
_queueObserver ( observer ) {
346
373
if ( this . _isBroken ) {
347
374
if ( observer && observer . onError ) {
348
375
observer . onError ( this . _error ) ;
349
376
}
350
- return ;
377
+ return false ;
351
378
}
352
379
observer = observer || NO_OP_OBSERVER ;
353
380
observer . onCompleted = observer . onCompleted || NO_OP ;
@@ -358,6 +385,7 @@ class Connection {
358
385
} else {
359
386
this . _pendingObservers . push ( observer ) ;
360
387
}
388
+ return true ;
361
389
}
362
390
363
391
/**
@@ -419,6 +447,15 @@ class Connection {
419
447
}
420
448
}
421
449
}
450
+
451
+ _handleProtocolError ( message ) {
452
+ this . _ackFailureMuted = false ;
453
+ this . _currentFailure = null ;
454
+ this . _updateCurrentObserver ( ) ;
455
+ const error = newError ( message , PROTOCOL_ERROR ) ;
456
+ this . _handleFatalError ( error ) ;
457
+ return error ;
458
+ }
422
459
}
423
460
424
461
class ConnectionState {
0 commit comments