Skip to content

Commit aa93910

Browse files
committed
Terminate active HTTP requests when session closed
All pending HTTP requests will now be aborted and failed when parent HTTP session is closed.
1 parent 56050cf commit aa93910

File tree

3 files changed

+44
-15
lines changed

3 files changed

+44
-15
lines changed

src/v1/internal/http/http-session.js

+1-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ export default class HttpSession extends Session {
2828
constructor(url, authToken, config) {
2929
super(WRITE, null, null, config);
3030
this._statementRunner = new HttpStatementRunner(url, authToken);
31-
this._outgoingXhrRequests = {};
3231
}
3332

3433
run(statement, parameters = {}) {
@@ -58,13 +57,7 @@ export default class HttpSession extends Session {
5857
}
5958

6059
close(callback = (() => null)) {
61-
Object.keys(this._outgoingXhrRequests).forEach(id => {
62-
const xhrRequest = this._outgoingXhrRequests[id];
63-
if (xhrRequest) {
64-
xhrRequest.abort();
65-
}
66-
delete this._outgoingXhrRequests[id];
67-
});
60+
this._statementRunner.terminateActiveRequests();
6861
callback();
6962
}
7063
}

src/v1/internal/http/http-statement-runner.js

+22-7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import StreamObserver from '../stream-observer';
2222
import Result from '../../result';
2323
import {EMPTY_CONNECTION_HOLDER} from '../connection-holder';
2424
import HttpDataConverter from './http-data-converter';
25+
import {Neo4jError} from '../../error';
2526

2627
export default class HttpStatementRunner {
2728

@@ -30,13 +31,21 @@ export default class HttpStatementRunner {
3031
this._transactionCommitUrl = createTransactionCommitUrl(url);
3132
this._headers = createHttpHeaders(authToken);
3233
this._converter = new HttpDataConverter();
34+
this._activeXhrRequests = [];
3335
}
3436

3537
run(statement, parameters) {
3638
const streamObserver = new StreamObserver();
37-
sendPostRequest(statement, parameters, streamObserver, this._transactionCommitUrl, this._headers, this._converter);
39+
sendPostRequest(statement, parameters, streamObserver, this);
3840
return new Result(streamObserver, statement, parameters, this._serverInfoSupplier, EMPTY_CONNECTION_HOLDER);
3941
}
42+
43+
terminateActiveRequests() {
44+
while (this._activeXhrRequests.length > 0) {
45+
const activeXhrRequest = this._activeXhrRequests.pop();
46+
activeXhrRequest.abort();
47+
}
48+
}
4049
}
4150

4251
function createServerInfoSupplier(url) {
@@ -58,16 +67,22 @@ function createHttpHeaders(authToken) {
5867
};
5968
}
6069

61-
function sendPostRequest(statement, parameters, streamObserver, transactionCommitUrl, headers, converter) {
70+
function sendPostRequest(statement, parameters, streamObserver, statementRunner) {
6271
try {
63-
xhr.post(
64-
transactionCommitUrl,
72+
const xhrRequest = xhr.post(
73+
statementRunner._transactionCommitUrl,
6574
{
66-
headers: headers,
67-
body: createStatementJson(statement, parameters, converter)
75+
headers: statementRunner._headers,
76+
body: createStatementJson(statement, parameters, statementRunner._converter)
6877
},
69-
(error, response) => processPostResponse(error, response, converter, streamObserver)
78+
(error, response) => processPostResponse(error, response, statementRunner._converter, streamObserver)
7079
);
80+
81+
xhrRequest.addEventListener('abort', () => {
82+
streamObserver.onError(new Neo4jError('Query terminated because session has been closed'));
83+
}, false);
84+
85+
statementRunner._activeXhrRequests.push(xhrRequest);
7186
} catch (e) {
7287
streamObserver.onError(e);
7388
}

test/internal/http-driver.test.js

+21
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,27 @@ describe('http driver', () => {
179179
});
180180
});
181181

182+
it('should terminate run when session is closed', done => {
183+
const boltSession = boltDriver.session();
184+
boltSession.run('CREATE (:Node)').then(() => {
185+
const tx = boltSession.beginTransaction();
186+
tx.run(`MATCH (n:Node) SET n.name = 'Thor' RETURN n`).then(() => {
187+
188+
const httpSession = httpDriver.session();
189+
httpSession.run(`MATCH (n:Node) SET n.name = 'Loki' RETURN n`).catch(error => {
190+
expect(error.name).toEqual('Neo4jError');
191+
expect(error.message).toEqual('Query terminated because session has been closed');
192+
done();
193+
});
194+
195+
// close http session after a second
196+
setTimeout(() => {
197+
httpSession.close();
198+
}, 1000);
199+
});
200+
});
201+
}, 10000);
202+
182203
function testSendAndReceiveWithReturnQuery(values, done) {
183204
const query = 'RETURN $value';
184205

0 commit comments

Comments
 (0)