Skip to content

Commit f207842

Browse files
committed
Retry on empty writer list
If the response from `getServers` contains an empty `writers` list we should reject that answer and procede to the next available router.
1 parent 0ce9982 commit f207842

File tree

5 files changed

+92
-57
lines changed

5 files changed

+92
-57
lines changed

src/v1/internal/round-robin-array.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class RoundRobinArray {
2626
this._index = 0;
2727
}
2828

29-
hop() {
29+
next() {
3030
let elem = this._items[this._index];
3131
if (this._items.length === 0) {
3232
this._index = 0;

src/v1/routing-driver.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class RoutingDriver extends Driver {
8888
return Promise.resolve(this._clusterView);
8989
} else {
9090
let call = () => {
91-
let conn = this._pool.acquire(routers.hop());
91+
let conn = this._pool.acquire(routers.next());
9292
let session = this._createSession(Promise.resolve(conn));
9393
return newClusterView(session).catch((err) => {
9494
this._forget(conn);
@@ -128,13 +128,13 @@ class RoutingDriver extends Driver {
128128
//update our cached view
129129
this._clusterView = view;
130130
if (m === READ) {
131-
let key = view.readers.hop();
131+
let key = view.readers.next();
132132
if (!key) {
133133
return Promise.reject(newError('No read servers available', SESSION_EXPIRED));
134134
}
135135
return this._pool.acquire(key);
136136
} else if (m === WRITE) {
137-
let key = view.writers.hop();
137+
let key = view.writers.next();
138138
if (!key) {
139139
return Promise.reject(newError('No write servers available', SESSION_EXPIRED));
140140
}
@@ -237,6 +237,9 @@ function newClusterView(session) {
237237
readers.pushAll(addresses);
238238
}
239239
}
240+
if (routers.empty() || writers.empty()) {
241+
return Promise.reject(newError("Invalid routing response from server", SERVICE_UNAVAILABLE))
242+
}
240243
return new ClusterView(routers, readers, writers, expires);
241244
})
242245
.catch((e) => {

test/internal/round-robin-array.test.js

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -23,104 +23,104 @@ describe('round-robin-array', function() {
2323
it('should step through array', function () {
2424
var array = new RoundRobinArray([1,2,3,4,5]);
2525

26-
expect(array.hop()).toEqual(1);
27-
expect(array.hop()).toEqual(2);
28-
expect(array.hop()).toEqual(3);
29-
expect(array.hop()).toEqual(4);
30-
expect(array.hop()).toEqual(5);
31-
expect(array.hop()).toEqual(1);
32-
expect(array.hop()).toEqual(2);
26+
expect(array.next()).toEqual(1);
27+
expect(array.next()).toEqual(2);
28+
expect(array.next()).toEqual(3);
29+
expect(array.next()).toEqual(4);
30+
expect(array.next()).toEqual(5);
31+
expect(array.next()).toEqual(1);
32+
expect(array.next()).toEqual(2);
3333
//....
3434
});
3535

3636
it('should step through single element array', function () {
3737
var array = new RoundRobinArray([5]);
3838

39-
expect(array.hop()).toEqual(5);
40-
expect(array.hop()).toEqual(5);
41-
expect(array.hop()).toEqual(5);
39+
expect(array.next()).toEqual(5);
40+
expect(array.next()).toEqual(5);
41+
expect(array.next()).toEqual(5);
4242
//....
4343
});
4444

4545
it('should handle deleting item before current ', function () {
4646
var array = new RoundRobinArray([1,2,3,4,5]);
4747

48-
expect(array.hop()).toEqual(1);
49-
expect(array.hop()).toEqual(2);
48+
expect(array.next()).toEqual(1);
49+
expect(array.next()).toEqual(2);
5050
array.remove(2);
51-
expect(array.hop()).toEqual(3);
52-
expect(array.hop()).toEqual(4);
53-
expect(array.hop()).toEqual(5);
54-
expect(array.hop()).toEqual(1);
55-
expect(array.hop()).toEqual(3);
51+
expect(array.next()).toEqual(3);
52+
expect(array.next()).toEqual(4);
53+
expect(array.next()).toEqual(5);
54+
expect(array.next()).toEqual(1);
55+
expect(array.next()).toEqual(3);
5656
//....
5757
});
5858

5959
it('should handle deleting item on current ', function () {
6060
var array = new RoundRobinArray([1,2,3,4,5]);
6161

62-
expect(array.hop()).toEqual(1);
63-
expect(array.hop()).toEqual(2);
62+
expect(array.next()).toEqual(1);
63+
expect(array.next()).toEqual(2);
6464
array.remove(3);
65-
expect(array.hop()).toEqual(4);
66-
expect(array.hop()).toEqual(5);
67-
expect(array.hop()).toEqual(1);
68-
expect(array.hop()).toEqual(2);
69-
expect(array.hop()).toEqual(4);
65+
expect(array.next()).toEqual(4);
66+
expect(array.next()).toEqual(5);
67+
expect(array.next()).toEqual(1);
68+
expect(array.next()).toEqual(2);
69+
expect(array.next()).toEqual(4);
7070
//....
7171
});
7272

7373
it('should handle deleting item after current ', function () {
7474
var array = new RoundRobinArray([1,2,3,4,5]);
7575

76-
expect(array.hop()).toEqual(1);
77-
expect(array.hop()).toEqual(2);
76+
expect(array.next()).toEqual(1);
77+
expect(array.next()).toEqual(2);
7878
array.remove(4);
79-
expect(array.hop()).toEqual(3);
80-
expect(array.hop()).toEqual(5);
81-
expect(array.hop()).toEqual(1);
82-
expect(array.hop()).toEqual(2);
83-
expect(array.hop()).toEqual(3);
79+
expect(array.next()).toEqual(3);
80+
expect(array.next()).toEqual(5);
81+
expect(array.next()).toEqual(1);
82+
expect(array.next()).toEqual(2);
83+
expect(array.next()).toEqual(3);
8484
//....
8585
});
8686

8787
it('should handle deleting last item ', function () {
8888
var array = new RoundRobinArray([1,2,3,4,5]);
8989

90-
expect(array.hop()).toEqual(1);
91-
expect(array.hop()).toEqual(2);
92-
expect(array.hop()).toEqual(3);
93-
expect(array.hop()).toEqual(4);
90+
expect(array.next()).toEqual(1);
91+
expect(array.next()).toEqual(2);
92+
expect(array.next()).toEqual(3);
93+
expect(array.next()).toEqual(4);
9494
array.remove(5);
95-
expect(array.hop()).toEqual(1);
96-
expect(array.hop()).toEqual(2);
97-
expect(array.hop()).toEqual(3);
98-
expect(array.hop()).toEqual(4);
99-
expect(array.hop()).toEqual(1);
95+
expect(array.next()).toEqual(1);
96+
expect(array.next()).toEqual(2);
97+
expect(array.next()).toEqual(3);
98+
expect(array.next()).toEqual(4);
99+
expect(array.next()).toEqual(1);
100100
//....
101101
});
102102

103103
it('should handle deleting first item ', function () {
104104
var array = new RoundRobinArray([1,2,3,4,5]);
105105
array.remove(1);
106-
expect(array.hop()).toEqual(2);
107-
expect(array.hop()).toEqual(3);
108-
expect(array.hop()).toEqual(4);
109-
expect(array.hop()).toEqual(5);
110-
expect(array.hop()).toEqual(2);
111-
expect(array.hop()).toEqual(3);
112-
expect(array.hop()).toEqual(4);
113-
expect(array.hop()).toEqual(5);
106+
expect(array.next()).toEqual(2);
107+
expect(array.next()).toEqual(3);
108+
expect(array.next()).toEqual(4);
109+
expect(array.next()).toEqual(5);
110+
expect(array.next()).toEqual(2);
111+
expect(array.next()).toEqual(3);
112+
expect(array.next()).toEqual(4);
113+
expect(array.next()).toEqual(5);
114114
//....
115115
});
116116

117117
it('should handle deleting multiple items ', function () {
118118
var array = new RoundRobinArray([1,2,3,1,1]);
119119
array.remove(1);
120-
expect(array.hop()).toEqual(2);
121-
expect(array.hop()).toEqual(3);
122-
expect(array.hop()).toEqual(2);
123-
expect(array.hop()).toEqual(3);
120+
expect(array.next()).toEqual(2);
121+
expect(array.next()).toEqual(3);
122+
expect(array.next()).toEqual(2);
123+
expect(array.next()).toEqual(3);
124124
//....
125125
});
126126

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
!: AUTO INIT
2+
!: AUTO RESET
3+
!: AUTO PULL_ALL
4+
5+
C: RUN "CALL dbms.cluster.routing.getServers" {}
6+
PULL_ALL
7+
S: SUCCESS {"fields": ["ttl", "servers"]}
8+
RECORD [9223372036854775807, [{"addresses": [],"role": "WRITE"}, {"addresses": ["127.0.0.1:9005","127.0.0.1:9006"], "role": "READ"},{"addresses": ["127.0.0.1:9001","127.0.0.1:9002","127.0.0.1:9003"], "role": "ROUTE"}]]
9+
SUCCESS {}

test/v1/routing.driver.boltkit.it.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ describe('routing driver ', function () {
201201

202202
kit.run(function () {
203203
var driver = neo4j.driver("bolt+routing://127.0.0.1:9000", neo4j.auth.basic("neo4j", "neo4j"));
204-
//driver.onError = console.log;
205204
// When
206205
var session = driver.session(neo4j.session.READ);
207206
session.run("MATCH (n) RETURN n.name").then(function (res) {
@@ -617,5 +616,29 @@ describe('routing driver ', function () {
617616
});
618617
});
619618
});
619+
620+
it('should fail if missing write server', function (done) {
621+
if (!boltkit.BoltKitSupport) {
622+
done();
623+
return;
624+
}
625+
// Given
626+
var kit = new boltkit.BoltKit();
627+
var seedServer = kit.start('./test/resources/boltkit/no_writers.script', 9001);
628+
629+
kit.run(function () {
630+
var driver = neo4j.driver("bolt+routing://127.0.0.1:9001", neo4j.auth.basic("neo4j", "neo4j"));
631+
// When
632+
var session = driver.session(neo4j.session.WRITE);
633+
session.run("MATCH (n) RETURN n.name").catch(function (err) {
634+
expect(err.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE);
635+
driver.close();
636+
seedServer.exit(function (code) {
637+
expect(code).toEqual(0);
638+
done();
639+
});
640+
});
641+
});
642+
});
620643
});
621644

0 commit comments

Comments
 (0)