Skip to content

Commit e105ee4

Browse files
authored
Merge pull request neo4j#413 from lutovich/1.7-goodbye-msg
Send GOODBYE message before closing connections in Bolt V3
2 parents 92a946d + dd54562 commit e105ee4

10 files changed

+114
-4
lines changed

src/v1/internal/bolt-protocol-v1.js

+4
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ export default class BoltProtocol {
7272
this._connection.write(message, observer, true);
7373
}
7474

75+
prepareToClose(observer) {
76+
// no need to notify the database in this protocol version
77+
}
78+
7579
/**
7680
* Begin an explicit transaction.
7781
* @param {Bookmark} bookmark the bookmark.

src/v1/internal/bolt-protocol-v3.js

+5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ export default class BoltProtocol extends BoltProtocolV2 {
4747
this._connection.write(message, observer, true);
4848
}
4949

50+
prepareToClose(observer) {
51+
const message = RequestMessage.goodbye();
52+
this._connection.write(message, observer, true);
53+
}
54+
5055
beginTransaction(bookmark, txConfig, observer) {
5156
prepareToHandleSingleResponse(observer);
5257
const message = RequestMessage.begin(bookmark, txConfig);

src/v1/internal/connection.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -382,11 +382,23 @@ export default class Connection {
382382
* Call close on the channel.
383383
* @param {function} cb - Function to call on close.
384384
*/
385-
close(cb) {
385+
close(cb = (() => null)) {
386386
if (this._log.isDebugEnabled()) {
387387
this._log.debug(`${this} closing`);
388388
}
389-
this._ch.close(cb);
389+
390+
if (this._protocol) {
391+
// protocol has been initialized
392+
// use it to notify the database about the upcoming close of the connection
393+
this._protocol.prepareToClose(NO_OP_OBSERVER);
394+
}
395+
396+
this._ch.close(() => {
397+
if (this._log.isDebugEnabled()) {
398+
this._log.debug(`${this} closed`);
399+
}
400+
cb();
401+
});
390402
}
391403

392404
toString() {

src/v1/internal/request-message.js

+10
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const DISCARD_ALL = 0x2F; // 0010 1111 // DISCARD_ALL - unused
2626
const PULL_ALL = 0x3F; // 0011 1111 // PULL_ALL
2727

2828
const HELLO = 0x01; // 0000 0001 // HELLO <metadata>
29+
const GOODBYE = 0x02; // 0000 0010 // GOODBYE
2930
const BEGIN = 0x11; // 0001 0001 // BEGIN <metadata>
3031
const COMMIT = 0x12; // 0001 0010 // COMMIT
3132
const ROLLBACK = 0x13; // 0001 0011 // ROLLBACK
@@ -125,6 +126,14 @@ export default class RequestMessage {
125126
return new RequestMessage(RUN, [statement, parameters, metadata],
126127
() => `RUN ${statement} ${JSON.stringify(parameters)} ${JSON.stringify(metadata)}`);
127128
}
129+
130+
/**
131+
* Get a GOODBYE message.
132+
* @return {RequestMessage} the GOODBYE message.
133+
*/
134+
static goodbye() {
135+
return GOODBYE_MESSAGE;
136+
}
128137
}
129138

130139
/**
@@ -152,3 +161,4 @@ const PULL_ALL_MESSAGE = new RequestMessage(PULL_ALL, [], () => 'PULL_ALL');
152161
const RESET_MESSAGE = new RequestMessage(RESET, [], () => 'RESET');
153162
const COMMIT_MESSAGE = new RequestMessage(COMMIT, [], () => 'COMMIT');
154163
const ROLLBACK_MESSAGE = new RequestMessage(ROLLBACK, [], () => 'ROLLBACK');
164+
const GOODBYE_MESSAGE = new RequestMessage(GOODBYE, [], () => 'GOODBYE');

test/internal/connection.test.js

+24
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import ConnectionErrorHandler from '../../src/v1/internal/connection-error-handl
3232
import testUtils from '../internal/test-utils';
3333
import Bookmark from '../../src/v1/internal/bookmark';
3434
import TxConfig from '../../src/v1/internal/tx-config';
35+
import boltStub from '../internal/bolt-stub';
3536

3637
const ILLEGAL_MESSAGE = {signature: 42, fields: []};
3738
const SUCCESS_MESSAGE = {signature: 0x70, fields: [{}]};
@@ -346,6 +347,29 @@ describe('Connection', () => {
346347
connection._handleFatalError(newError('Hello', SERVICE_UNAVAILABLE));
347348
});
348349

350+
it('should send hello and goodbye messages', done => {
351+
if (!boltStub.supported) {
352+
done();
353+
return;
354+
}
355+
356+
const server = boltStub.start('./test/resources/boltstub/hello_goodbye.script', 9001);
357+
358+
boltStub.run(() => {
359+
connection = createConnection('bolt://127.0.0.1:9001', {encrypted: false});
360+
connection.connect('single-connection/1.2.3', basicAuthToken())
361+
.then(() => {
362+
connection.close(() => {
363+
server.exit(code => {
364+
expect(code).toEqual(0);
365+
done();
366+
});
367+
});
368+
})
369+
.catch(error => done.fail(error));
370+
});
371+
});
372+
349373
function packedHandshakeMessage() {
350374
const result = alloc(4);
351375
result.putInt32(0, 1);

test/internal/request-message.test.js

+7
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,11 @@ describe('RequestMessage', () => {
115115
expect(message.toString()).toEqual(`RUN ${statement} ${JSON.stringify(parameters)} ${JSON.stringify(expectedMetadata)}`);
116116
});
117117

118+
it('should create GOODBYE message', () => {
119+
const message = RequestMessage.goodbye();
120+
121+
expect(message.signature).toEqual(0x02);
122+
expect(message.fields).toEqual([]);
123+
expect(message.toString()).toEqual('GOODBYE');
124+
});
118125
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
!: BOLT 3
2+
3+
C: HELLO {"credentials": "password", "scheme": "basic", "user_agent": "single-connection/1.2.3", "principal": "neo4j"}
4+
S: SUCCESS {"server": "Neo4j/9.9.9"}
5+
C: GOODBYE
6+
S: <EXIT>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
!: BOLT 3
2+
!: AUTO RESET
3+
4+
C: HELLO {"credentials": "password", "scheme": "basic", "user_agent": "neo4j-javascript/0.0.0-dev", "principal": "neo4j"}
5+
S: SUCCESS {"server": "Neo4j/9.9.9"}
6+
C: RUN "MATCH (n) RETURN n.name" {} {}
7+
PULL_ALL
8+
S: SUCCESS {"fields": ["n.name"]}
9+
RECORD ["Foo"]
10+
RECORD ["Bar"]
11+
SUCCESS {}
12+
C: GOODBYE
13+
S: <EXIT>

test/resources/boltstub/query_with_error.script

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ C: PULL_ALL
66
S: FAILURE {"code": "Neo.ClientError.Statement.ArithmeticError", "message": "/ by zero"}
77
S: IGNORED
88
C: RESET
9-
S: SUCCESS
9+
S: SUCCESS {}
1010
C: RESET
11-
S: SUCCESS
11+
S: SUCCESS {}

test/v1/direct.driver.boltkit.test.js

+29
Original file line numberDiff line numberDiff line change
@@ -333,4 +333,33 @@ describe('direct driver with stub server', () => {
333333
});
334334
});
335335

336+
it('should send goodbye message when closed', done => {
337+
if (!boltStub.supported) {
338+
done();
339+
return;
340+
}
341+
342+
const server = boltStub.start('./test/resources/boltstub/hello_run_goodbye.script', 9001);
343+
344+
boltStub.run(() => {
345+
const driver = boltStub.newDriver('bolt://127.0.0.1:9001');
346+
const session = driver.session();
347+
348+
session.run('MATCH (n) RETURN n.name')
349+
.then(result => {
350+
const names = result.records.map(record => record.get('n.name'));
351+
expect(names).toEqual(['Foo', 'Bar']);
352+
353+
session.close(() => {
354+
driver.close();
355+
server.exit(code => {
356+
expect(code).toEqual(0);
357+
done();
358+
});
359+
});
360+
})
361+
.catch(error => done.fail(error));
362+
});
363+
});
364+
336365
});

0 commit comments

Comments
 (0)