1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const GetClusterTopologyCommand_1 = require("../ServerWide/Commands/GetClusterTopologyCommand");
|
4 | const NodeSelector_1 = require("./NodeSelector");
|
5 | const os = require("os");
|
6 | const BluebirdPromise = require("bluebird");
|
7 | const semaphore = require("semaphore");
|
8 | const LogUtil_1 = require("../Utility/LogUtil");
|
9 | const RequestExecutor_1 = require("./RequestExecutor");
|
10 | const __1 = require("..");
|
11 | const Exceptions_1 = require("../Exceptions");
|
12 | const ServerNode_1 = require("./ServerNode");
|
13 | const Topology_1 = require("./Topology");
|
14 | const GetTcpInfoCommand_1 = require("../ServerWide/Commands/GetTcpInfoCommand");
|
15 | const SemaphoreUtil_1 = require("../Utility/SemaphoreUtil");
|
16 | const log = LogUtil_1.getLogger({ module: "ClusterRequestExecutor" });
|
17 | class ClusterRequestExecutor extends RequestExecutor_1.RequestExecutor {
|
18 | constructor(authOptions, conventions) {
|
19 | super(null, authOptions, conventions);
|
20 | this._clusterTopologySemaphore = semaphore();
|
21 | }
|
22 | static createForSingleNodeWithConfigurationUpdates(url, databaseName, opts) {
|
23 | return Exceptions_1.throwError("NotSupportedException");
|
24 | }
|
25 | static createForSingleNodeWithoutConfigurationUpdates(url, databaseName, opts) {
|
26 | return Exceptions_1.throwError("NotSupportedException");
|
27 | }
|
28 | static createForSingleNode(url, opts) {
|
29 | const initialUrls = [url];
|
30 | const { authOptions, documentConventions } = opts;
|
31 | const urls = this._validateUrls(initialUrls, authOptions);
|
32 | const executor = new ClusterRequestExecutor(authOptions, documentConventions || __1.DocumentConventions.defaultConventions);
|
33 | const serverNode = new ServerNode_1.ServerNode({ url });
|
34 | const topology = new Topology_1.Topology(-1, [serverNode]);
|
35 | const nodeSelector = new NodeSelector_1.NodeSelector(topology);
|
36 | executor._nodeSelector = nodeSelector;
|
37 | executor._topologyEtag = -2;
|
38 | executor._disableClientConfigurationUpdates = true;
|
39 | executor._disableTopologyUpdates = true;
|
40 | return executor;
|
41 | }
|
42 | static create(initialUrls, databaseOrOpts, opts) {
|
43 | if (typeof (databaseOrOpts) === "string") {
|
44 | return Exceptions_1.throwError("NotSupportedException");
|
45 | }
|
46 | const { authOptions, documentConventions } = (opts || databaseOrOpts) || {};
|
47 | const executor = new ClusterRequestExecutor(authOptions, documentConventions ? documentConventions : __1.DocumentConventions.defaultConventions);
|
48 | executor._disableClientConfigurationUpdates = true;
|
49 | executor._firstTopologyUpdatePromise = executor._firstTopologyUpdate(initialUrls);
|
50 | return executor;
|
51 | }
|
52 | _performHealthCheck(serverNode, nodeIndex) {
|
53 | return this.execute(new GetTcpInfoCommand_1.GetTcpInfoCommand("health-check"), null, {
|
54 | chosenNode: serverNode,
|
55 | nodeIndex,
|
56 | shouldRetry: false
|
57 | });
|
58 | }
|
59 | updateTopology(node, timeout, forceUpdate) {
|
60 | if (this._disposed) {
|
61 | return Promise.resolve(false);
|
62 | }
|
63 | const acquiredSemContext = SemaphoreUtil_1.acquireSemaphore(this._clusterTopologySemaphore, { timeout });
|
64 | const result = BluebirdPromise.resolve(acquiredSemContext.promise)
|
65 | .then(() => {
|
66 | if (this._disposed) {
|
67 | return false;
|
68 | }
|
69 | const command = new GetClusterTopologyCommand_1.GetClusterTopologyCommand();
|
70 | return this.execute(command, null, {
|
71 | chosenNode: node,
|
72 | nodeIndex: null,
|
73 | shouldRetry: false
|
74 | })
|
75 | .then(() => {
|
76 | const results = command.result;
|
77 | const members = results.topology.members;
|
78 | const nodes = Object.keys(members)
|
79 | .reduce((reduceResult, clusterTag) => {
|
80 | const url = members[clusterTag];
|
81 | const serverNode = new ServerNode_1.ServerNode({ clusterTag, url });
|
82 | return [...reduceResult, serverNode];
|
83 | }, []);
|
84 | const newTopology = new Topology_1.Topology(0, nodes);
|
85 | if (!this._nodeSelector) {
|
86 | this._nodeSelector = new NodeSelector_1.NodeSelector(newTopology);
|
87 | if (this._readBalanceBehavior === "FastestNode") {
|
88 | this._nodeSelector.scheduleSpeedTest();
|
89 | }
|
90 | }
|
91 | else if (this._nodeSelector.onUpdateTopology(newTopology, forceUpdate)) {
|
92 | this._disposeAllFailedNodesTimers();
|
93 | if (this._readBalanceBehavior === "FastestNode") {
|
94 | this._nodeSelector.scheduleSpeedTest();
|
95 | }
|
96 | }
|
97 | })
|
98 | .then(() => true);
|
99 | }, (reason) => {
|
100 | if (reason.name === "TimeoutError") {
|
101 | return false;
|
102 | }
|
103 | throw reason;
|
104 | })
|
105 | .finally(() => acquiredSemContext.dispose());
|
106 | return Promise.resolve(result);
|
107 | }
|
108 | _updateClientConfigurationAsync() {
|
109 | return Promise.resolve();
|
110 | }
|
111 | _throwExceptions(details) {
|
112 | Exceptions_1.throwError("InvalidOperationException", "Failed to retrieve cluster topology from all known nodes" + os.EOL + details);
|
113 | }
|
114 | dispose() {
|
115 | this._clusterTopologySemaphore.take(() => {
|
116 | });
|
117 | super.dispose();
|
118 | }
|
119 | }
|
120 | exports.ClusterRequestExecutor = ClusterRequestExecutor;
|