Skip to content

Commit d611151

Browse files
committed
Deprecate active failover
Fixes DE-746.
1 parent b70940d commit d611151

File tree

3 files changed

+12
-168
lines changed

3 files changed

+12
-168
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ This driver uses semantic versioning:
2323
The ZKD index type was previously marked as experimental and has now been
2424
finalized and renamed to MDI in ArangoDB 3.12.
2525

26+
### Deprecated
27+
28+
- Deprecated active failover support (DE-746)
29+
30+
Active failover is no longer be supported in ArangoDB 3.12 and later. This
31+
functionality will be removed from the driver in a future release.
32+
2633
## [8.7.0] - 2024-02-14
2734

2835
### Changed

src/connection.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,9 @@ export type Config = {
326326
/**
327327
* Base URL of the ArangoDB server or list of server URLs.
328328
*
329-
* When working with a cluster or a single server with leader/follower
330-
* failover, the method {@link database.Database#acquireHostList} can be used to
331-
* automatically pick up additional coordinators/followers at any point.
329+
* When working with a cluster, the method {@link database.Database#acquireHostList}
330+
* can be used to automatically pick up additional coordinators/followers at
331+
* any point.
332332
*
333333
* When running ArangoDB on a unix socket, e.g. `/tmp/arangodb.sock`, the
334334
* following URL formats are supported for unix sockets:
@@ -404,8 +404,8 @@ export type Config = {
404404
* or the request has been retried a total of `maxRetries` number of times
405405
* (not including the initial failed request).
406406
*
407-
* When working with a single server without leader/follower failover, the
408-
* retries (if any) will be made to the same server.
407+
* When working with a single server, the retries (if any) will be made to
408+
* the same server.
409409
*
410410
* This setting currently has no effect when using arangojs in a browser.
411411
*

src/test/99-load-balancing.ts

Lines changed: 0 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
1-
import Instance from "arangodb-instance-manager/lib/Instance";
21
import InstanceManager from "arangodb-instance-manager/lib/InstanceManager";
32
import { expect } from "chai";
43
import { resolve } from "path";
5-
import { DocumentCollection } from "../collection";
64
import { Connection } from "../connection";
75
import { Database } from "../database";
86

9-
async function sleep(ms: number) {
10-
return new Promise<void>((resolve) => {
11-
setTimeout(() => resolve(), ms);
12-
});
13-
}
14-
157
let ARANGO_PATH = "";
168
let ARANGO_RUNNER: "local" | "docker";
179
if (process.env.RESILIENCE_ARANGO_BASEPATH) {
@@ -28,161 +20,6 @@ if (process.env.RESILIENCE_ARANGO_BASEPATH) {
2820
}
2921
const describeIm = ARANGO_PATH ? describe.only : describe.skip;
3022

31-
describeIm("Single-server active failover", function () {
32-
this.timeout(Infinity);
33-
let im: InstanceManager;
34-
let uuid: string;
35-
let leader: Instance;
36-
let db: Database;
37-
let conn: Connection;
38-
beforeEach(async () => {
39-
im = new InstanceManager(ARANGO_PATH, ARANGO_RUNNER, "rocksdb");
40-
await im.startAgency();
41-
await im.startSingleServer("arangojs", 2);
42-
await im.waitForAllInstances();
43-
uuid = await im.asyncReplicationLeaderSelected();
44-
leader = (await im.resolveUUID(uuid))!;
45-
db = new Database({ url: leader.endpoint });
46-
conn = (db as any)._connection;
47-
await db.acquireHostList();
48-
});
49-
afterEach(async function () {
50-
im.moveServerLogs(this.currentTest);
51-
const logs = await im.cleanup(this.currentTest!.isFailed());
52-
// eslint-disable-next-line no-console
53-
if (logs) console.error(`IM Logs:\n${logs}`);
54-
});
55-
async function getServerId(): Promise<string | undefined> {
56-
const res = await db.route("_api/replication/server-id").get();
57-
return res.body.serverId;
58-
}
59-
async function responseHeaders() {
60-
const res = await db.route("_api/version").get();
61-
return res.headers;
62-
}
63-
it.skip("failover to follower if leader is down", async function () {
64-
// This test times out on GitHub Actions during leader selection.
65-
// This is likely an issue with the Instance Manager, not arangojs.
66-
expect((conn as any)._hostUrls).to.have.lengthOf(2);
67-
(conn as any)._activeHostUrl = (conn as any)._hostUrls[0];
68-
const leaderId = await getServerId();
69-
expect(leaderId).not.to.be.empty;
70-
const headers = await responseHeaders();
71-
expect(headers).not.to.include.keys("x-arango-endpoint");
72-
73-
await im.kill(leader);
74-
await im.asyncReplicationLeaderSelected(uuid as any);
75-
await sleep(3000);
76-
await db.version(); // cycle
77-
78-
const newLeaderId = await getServerId();
79-
expect(newLeaderId).not.to.be.empty;
80-
expect(newLeaderId).not.to.equal(leaderId);
81-
});
82-
it("redirect to leader if server is not leader", async () => {
83-
expect((conn as any)._hostUrls).to.have.lengthOf(2);
84-
85-
(conn as any)._activeHostUrl = (conn as any)._hostUrls[0];
86-
const leaderId = await getServerId();
87-
expect(leaderId).not.to.be.empty;
88-
const leaderHeaders = await responseHeaders();
89-
expect(leaderHeaders).not.to.include.keys("x-arango-endpoint");
90-
91-
(conn as any)._activeHostUrl = (conn as any)._hostUrls[1];
92-
const followerId = await getServerId();
93-
expect(followerId).not.to.be.empty;
94-
expect(followerId).not.to.equal(leaderId);
95-
const followerHeaders = await responseHeaders();
96-
expect(followerHeaders).to.include.keys("x-arango-endpoint");
97-
(conn as any)._hosts.shift();
98-
(conn as any)._hostUrls.shift();
99-
(conn as any)._activeHostUrl = (conn as any)._hostUrls[0];
100-
expect((conn as any)._hostUrls).to.have.lengthOf(1);
101-
102-
await db.createCollection(`test_${Date.now()}`);
103-
const newLeaderId = await getServerId();
104-
expect(newLeaderId).not.to.be.empty;
105-
expect(newLeaderId).to.equal(leaderId);
106-
expect((conn as any)._hostUrls).to.have.lengthOf(2);
107-
});
108-
});
109-
110-
describeIm("Single-server with follower", function () {
111-
this.timeout(Infinity);
112-
let im: InstanceManager;
113-
let leader: Instance;
114-
let db: Database;
115-
let conn: Connection;
116-
let collection: DocumentCollection;
117-
beforeEach(async () => {
118-
im = new InstanceManager(ARANGO_PATH, ARANGO_RUNNER);
119-
await im.startAgency();
120-
await im.startSingleServer("arangojs", 2);
121-
await im.waitForAllInstances();
122-
leader = await im.asyncReplicationLeaderInstance();
123-
db = new Database({ url: leader.endpoint });
124-
conn = (db as any)._connection;
125-
await db.acquireHostList();
126-
collection = await db.createCollection("test");
127-
await db.waitForPropagation(
128-
{ path: `/_api/collection/${collection.name}` },
129-
10000
130-
);
131-
await collection.save({ _key: "abc" });
132-
await sleep(3000);
133-
});
134-
afterEach(async () => {
135-
await collection.drop();
136-
await sleep(3000);
137-
await im.cleanup();
138-
});
139-
async function getResponse(dirty?: boolean) {
140-
return await conn.request({
141-
method: "GET",
142-
path: "/_api/document/test/abc",
143-
allowDirtyRead: dirty,
144-
});
145-
}
146-
it("supports dirty reads", async () => {
147-
expect((conn as any)._hostUrls).to.have.lengthOf(2);
148-
const res1 = await getResponse(true);
149-
expect(res1.arangojsHostUrl).to.be.a("string");
150-
const headers1 = res1.request.getHeaders();
151-
expect(headers1).to.include.keys("x-arango-allow-dirty-read");
152-
const res2 = await getResponse(true);
153-
expect(res2.arangojsHostUrl).to.be.a("string");
154-
expect(res2.arangojsHostUrl).not.to.equal(res1.arangojsHostUrl);
155-
const headers2 = res2.request.getHeaders();
156-
expect(headers2).to.include.keys("x-arango-allow-dirty-read");
157-
});
158-
it("supports non-dirty reads", async () => {
159-
expect((conn as any)._hostUrls).to.have.lengthOf(2);
160-
const res1 = await getResponse();
161-
expect(res1.arangojsHostUrl).to.be.a("string");
162-
const headers1 = res1.request.getHeaders();
163-
expect(headers1).not.to.include.keys("x-arango-allow-dirty-read");
164-
const res2 = await getResponse();
165-
expect(res2.arangojsHostUrl).to.be.a("string");
166-
expect(res2.arangojsHostUrl).to.equal(res1.arangojsHostUrl);
167-
const headers2 = res2.request.getHeaders();
168-
expect(headers2).not.to.include.keys("x-arango-allow-dirty-read");
169-
});
170-
it("supports dirty read over multiple cursor batches", async () => {
171-
const cursor = await db.query(
172-
"FOR i IN 1..2 RETURN i",
173-
{},
174-
{
175-
allowDirtyRead: true,
176-
batchSize: 1,
177-
}
178-
);
179-
expect(cursor.hasNext).to.equal(true);
180-
expect(await cursor.next()).to.equal(1);
181-
expect(cursor.hasNext).to.equal(true);
182-
expect(await cursor.next()).to.equal(2);
183-
});
184-
});
185-
18623
describeIm("Cluster round robin", function () {
18724
this.timeout(Infinity);
18825
const NUM_COORDINATORS = 3;

0 commit comments

Comments
 (0)