mongodb 3.2.5 → 3.3.0-beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HISTORY.md +0 -10
- package/index.js +4 -4
- package/lib/admin.js +56 -56
- package/lib/aggregation_cursor.js +7 -3
- package/lib/bulk/common.js +18 -13
- package/lib/change_stream.js +196 -89
- package/lib/collection.js +217 -169
- package/lib/command_cursor.js +17 -7
- package/lib/core/auth/auth_provider.js +158 -0
- package/lib/core/auth/defaultAuthProviders.js +29 -0
- package/lib/core/auth/gssapi.js +241 -0
- package/lib/core/auth/mongo_credentials.js +81 -0
- package/lib/core/auth/mongocr.js +51 -0
- package/lib/core/auth/plain.js +35 -0
- package/lib/core/auth/scram.js +293 -0
- package/lib/core/auth/sspi.js +131 -0
- package/lib/core/auth/x509.js +26 -0
- package/lib/core/connection/apm.js +236 -0
- package/lib/core/connection/command_result.js +36 -0
- package/lib/core/connection/commands.js +507 -0
- package/lib/core/connection/connect.js +370 -0
- package/lib/core/connection/connection.js +624 -0
- package/lib/core/connection/logger.js +246 -0
- package/lib/core/connection/msg.js +219 -0
- package/lib/core/connection/pool.js +1285 -0
- package/lib/core/connection/utils.js +57 -0
- package/lib/core/cursor.js +752 -0
- package/lib/core/error.js +186 -0
- package/lib/core/index.js +50 -0
- package/lib/core/sdam/monitoring.js +228 -0
- package/lib/core/sdam/server.js +467 -0
- package/lib/core/sdam/server_description.js +163 -0
- package/lib/core/sdam/server_selectors.js +244 -0
- package/lib/core/sdam/srv_polling.js +135 -0
- package/lib/core/sdam/topology.js +1151 -0
- package/lib/core/sdam/topology_description.js +408 -0
- package/lib/core/sessions.js +711 -0
- package/lib/core/tools/smoke_plugin.js +61 -0
- package/lib/core/topologies/mongos.js +1337 -0
- package/lib/core/topologies/read_preference.js +202 -0
- package/lib/core/topologies/replset.js +1507 -0
- package/lib/core/topologies/replset_state.js +1121 -0
- package/lib/core/topologies/server.js +984 -0
- package/lib/core/topologies/shared.js +453 -0
- package/lib/core/transactions.js +167 -0
- package/lib/core/uri_parser.js +631 -0
- package/lib/core/utils.js +165 -0
- package/lib/core/wireprotocol/command.js +170 -0
- package/lib/core/wireprotocol/compression.js +73 -0
- package/lib/core/wireprotocol/constants.js +13 -0
- package/lib/core/wireprotocol/get_more.js +86 -0
- package/lib/core/wireprotocol/index.js +18 -0
- package/lib/core/wireprotocol/kill_cursors.js +70 -0
- package/lib/core/wireprotocol/query.js +224 -0
- package/lib/core/wireprotocol/shared.js +115 -0
- package/lib/core/wireprotocol/write_command.js +50 -0
- package/lib/cursor.js +40 -46
- package/lib/db.js +141 -95
- package/lib/dynamic_loaders.js +32 -0
- package/lib/error.js +12 -10
- package/lib/gridfs/chunk.js +2 -2
- package/lib/gridfs/grid_store.js +31 -25
- package/lib/gridfs-stream/index.js +4 -4
- package/lib/gridfs-stream/upload.js +1 -1
- package/lib/mongo_client.js +37 -15
- package/lib/operations/add_user.js +96 -0
- package/lib/operations/aggregate.js +24 -13
- package/lib/operations/aggregate_operation.js +127 -0
- package/lib/operations/bulk_write.js +104 -0
- package/lib/operations/close.js +47 -0
- package/lib/operations/collection_ops.js +28 -287
- package/lib/operations/collections.js +55 -0
- package/lib/operations/command.js +120 -0
- package/lib/operations/command_v2.js +43 -0
- package/lib/operations/common_functions.js +372 -0
- package/lib/operations/{mongo_client_ops.js → connect.js} +185 -157
- package/lib/operations/count.js +72 -0
- package/lib/operations/count_documents.js +46 -0
- package/lib/operations/create_collection.js +118 -0
- package/lib/operations/create_index.js +92 -0
- package/lib/operations/create_indexes.js +61 -0
- package/lib/operations/cursor_ops.js +3 -4
- package/lib/operations/db_ops.js +15 -12
- package/lib/operations/delete_many.js +25 -0
- package/lib/operations/delete_one.js +25 -0
- package/lib/operations/distinct.js +85 -0
- package/lib/operations/drop.js +53 -0
- package/lib/operations/drop_index.js +42 -0
- package/lib/operations/drop_indexes.js +23 -0
- package/lib/operations/estimated_document_count.js +33 -0
- package/lib/operations/execute_db_admin_command.js +34 -0
- package/lib/operations/execute_operation.js +165 -0
- package/lib/operations/explain.js +23 -0
- package/lib/operations/find_and_modify.js +98 -0
- package/lib/operations/find_one.js +33 -0
- package/lib/operations/find_one_and_delete.js +16 -0
- package/lib/operations/find_one_and_replace.js +18 -0
- package/lib/operations/find_one_and_update.js +19 -0
- package/lib/operations/geo_haystack_search.js +79 -0
- package/lib/operations/has_next.js +40 -0
- package/lib/operations/index_exists.js +39 -0
- package/lib/operations/index_information.js +23 -0
- package/lib/operations/indexes.js +22 -0
- package/lib/operations/insert_many.js +63 -0
- package/lib/operations/insert_one.js +75 -0
- package/lib/operations/is_capped.js +19 -0
- package/lib/operations/list_indexes.js +66 -0
- package/lib/operations/map_reduce.js +189 -0
- package/lib/operations/next.js +32 -0
- package/lib/operations/operation.js +63 -0
- package/lib/operations/options_operation.js +32 -0
- package/lib/operations/profiling_level.js +31 -0
- package/lib/operations/re_index.js +28 -0
- package/lib/operations/remove_user.js +52 -0
- package/lib/operations/rename.js +61 -0
- package/lib/operations/replace_one.js +47 -0
- package/lib/operations/set_profiling_level.js +48 -0
- package/lib/operations/stats.js +45 -0
- package/lib/operations/to_array.js +68 -0
- package/lib/operations/update_many.js +29 -0
- package/lib/operations/update_one.js +44 -0
- package/lib/operations/validate_collection.js +40 -0
- package/lib/read_concern.js +55 -0
- package/lib/topologies/mongos.js +3 -3
- package/lib/topologies/native_topology.js +22 -2
- package/lib/topologies/replset.js +3 -3
- package/lib/topologies/server.js +4 -4
- package/lib/topologies/topology_base.js +6 -6
- package/lib/url_parser.js +4 -3
- package/lib/utils.js +46 -59
- package/lib/write_concern.js +66 -0
- package/package.json +15 -6
- package/lib/.DS_Store +0 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const mongoErrorContextSymbol = Symbol('mongoErrorContextSymbol');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a new MongoError
|
|
7
|
+
*
|
|
8
|
+
* @augments Error
|
|
9
|
+
* @param {Error|string|object} message The error message
|
|
10
|
+
* @property {string} message The error message
|
|
11
|
+
* @property {string} stack The error call stack
|
|
12
|
+
*/
|
|
13
|
+
class MongoError extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
if (message instanceof Error) {
|
|
16
|
+
super(message.message);
|
|
17
|
+
this.stack = message.stack;
|
|
18
|
+
} else {
|
|
19
|
+
if (typeof message === 'string') {
|
|
20
|
+
super(message);
|
|
21
|
+
} else {
|
|
22
|
+
super(message.message || message.errmsg || message.$err || 'n/a');
|
|
23
|
+
for (var name in message) {
|
|
24
|
+
this[name] = message[name];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
Error.captureStackTrace(this, this.constructor);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.name = 'MongoError';
|
|
32
|
+
this[mongoErrorContextSymbol] = this[mongoErrorContextSymbol] || {};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new MongoError object
|
|
37
|
+
*
|
|
38
|
+
* @param {Error|string|object} options The options used to create the error.
|
|
39
|
+
* @return {MongoError} A MongoError instance
|
|
40
|
+
* @deprecated Use `new MongoError()` instead.
|
|
41
|
+
*/
|
|
42
|
+
static create(options) {
|
|
43
|
+
return new MongoError(options);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
hasErrorLabel(label) {
|
|
47
|
+
return this.errorLabels && this.errorLabels.indexOf(label) !== -1;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new MongoNetworkError
|
|
53
|
+
*
|
|
54
|
+
* @param {Error|string|object} message The error message
|
|
55
|
+
* @property {string} message The error message
|
|
56
|
+
* @property {string} stack The error call stack
|
|
57
|
+
*/
|
|
58
|
+
class MongoNetworkError extends MongoError {
|
|
59
|
+
constructor(message) {
|
|
60
|
+
super(message);
|
|
61
|
+
this.name = 'MongoNetworkError';
|
|
62
|
+
|
|
63
|
+
// This is added as part of the transactions specification
|
|
64
|
+
this.errorLabels = ['TransientTransactionError'];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* An error used when attempting to parse a value (like a connection string)
|
|
70
|
+
*
|
|
71
|
+
* @param {Error|string|object} message The error message
|
|
72
|
+
* @property {string} message The error message
|
|
73
|
+
*/
|
|
74
|
+
class MongoParseError extends MongoError {
|
|
75
|
+
constructor(message) {
|
|
76
|
+
super(message);
|
|
77
|
+
this.name = 'MongoParseError';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* An error signifying a timeout event
|
|
83
|
+
*
|
|
84
|
+
* @param {Error|string|object} message The error message
|
|
85
|
+
* @property {string} message The error message
|
|
86
|
+
*/
|
|
87
|
+
class MongoTimeoutError extends MongoError {
|
|
88
|
+
constructor(message) {
|
|
89
|
+
super(message);
|
|
90
|
+
this.name = 'MongoTimeoutError';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function makeWriteConcernResultObject(input) {
|
|
95
|
+
const output = Object.assign({}, input);
|
|
96
|
+
|
|
97
|
+
if (output.ok === 0) {
|
|
98
|
+
output.ok = 1;
|
|
99
|
+
delete output.errmsg;
|
|
100
|
+
delete output.code;
|
|
101
|
+
delete output.codeName;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return output;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* An error thrown when the server reports a writeConcernError
|
|
109
|
+
*
|
|
110
|
+
* @param {Error|string|object} message The error message
|
|
111
|
+
* @param {object} result The result document (provided if ok: 1)
|
|
112
|
+
* @property {string} message The error message
|
|
113
|
+
* @property {object} [result] The result document (provided if ok: 1)
|
|
114
|
+
*/
|
|
115
|
+
class MongoWriteConcernError extends MongoError {
|
|
116
|
+
constructor(message, result) {
|
|
117
|
+
super(message);
|
|
118
|
+
this.name = 'MongoWriteConcernError';
|
|
119
|
+
|
|
120
|
+
if (result != null) {
|
|
121
|
+
this.result = makeWriteConcernResultObject(result);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// see: https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.rst#terms
|
|
127
|
+
const RETRYABLE_ERROR_CODES = new Set([
|
|
128
|
+
6, // HostUnreachable
|
|
129
|
+
7, // HostNotFound
|
|
130
|
+
89, // NetworkTimeout
|
|
131
|
+
91, // ShutdownInProgress
|
|
132
|
+
189, // PrimarySteppedDown
|
|
133
|
+
9001, // SocketException
|
|
134
|
+
10107, // NotMaster
|
|
135
|
+
11600, // InterruptedAtShutdown
|
|
136
|
+
11602, // InterruptedDueToReplStateChange
|
|
137
|
+
13435, // NotMasterNoSlaveOk
|
|
138
|
+
13436 // NotMasterOrSecondary
|
|
139
|
+
]);
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Determines whether an error is something the driver should attempt to retry
|
|
143
|
+
*
|
|
144
|
+
* @param {MongoError|Error} error
|
|
145
|
+
*/
|
|
146
|
+
function isRetryableError(error) {
|
|
147
|
+
return (
|
|
148
|
+
RETRYABLE_ERROR_CODES.has(error.code) ||
|
|
149
|
+
error instanceof MongoNetworkError ||
|
|
150
|
+
error.message.match(/not master/) ||
|
|
151
|
+
error.message.match(/node is recovering/)
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const SDAM_UNRECOVERABLE_ERROR_CODES = new Set([
|
|
156
|
+
91, // ShutdownInProgress
|
|
157
|
+
189, // PrimarySteppedDown
|
|
158
|
+
10107, // NotMaster
|
|
159
|
+
11600, // InterruptedAtShutdown
|
|
160
|
+
11602, // InterruptedDueToReplStateChange
|
|
161
|
+
13435, // NotMasterNoSlaveOk
|
|
162
|
+
13436 // NotMasterOrSecondary
|
|
163
|
+
]);
|
|
164
|
+
/**
|
|
165
|
+
* Determines whether an error is a "node is recovering" error or a "not master" error for SDAM retryability.
|
|
166
|
+
* See https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#not-master-and-node-is-recovering
|
|
167
|
+
* @param {MongoError|Error} error
|
|
168
|
+
*/
|
|
169
|
+
function isSDAMUnrecoverableError(error) {
|
|
170
|
+
return (
|
|
171
|
+
SDAM_UNRECOVERABLE_ERROR_CODES.has(error.code) ||
|
|
172
|
+
(error.message &&
|
|
173
|
+
(error.message.match(/not master/) || error.message.match(/node is recovering/)))
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
module.exports = {
|
|
178
|
+
MongoError,
|
|
179
|
+
MongoNetworkError,
|
|
180
|
+
MongoParseError,
|
|
181
|
+
MongoTimeoutError,
|
|
182
|
+
MongoWriteConcernError,
|
|
183
|
+
mongoErrorContextSymbol,
|
|
184
|
+
isRetryableError,
|
|
185
|
+
isSDAMUnrecoverableError
|
|
186
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
let BSON = require('bson');
|
|
4
|
+
const require_optional = require('require_optional');
|
|
5
|
+
const EJSON = require('./utils').retrieveEJSON();
|
|
6
|
+
|
|
7
|
+
try {
|
|
8
|
+
// Attempt to grab the native BSON parser
|
|
9
|
+
const BSONNative = require_optional('bson-ext');
|
|
10
|
+
// If we got the native parser, use it instead of the
|
|
11
|
+
// Javascript one
|
|
12
|
+
if (BSONNative) {
|
|
13
|
+
BSON = BSONNative;
|
|
14
|
+
}
|
|
15
|
+
} catch (err) {} // eslint-disable-line
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
// Errors
|
|
19
|
+
MongoError: require('./error').MongoError,
|
|
20
|
+
MongoNetworkError: require('./error').MongoNetworkError,
|
|
21
|
+
MongoParseError: require('./error').MongoParseError,
|
|
22
|
+
MongoTimeoutError: require('./error').MongoTimeoutError,
|
|
23
|
+
MongoWriteConcernError: require('./error').MongoWriteConcernError,
|
|
24
|
+
mongoErrorContextSymbol: require('./error').mongoErrorContextSymbol,
|
|
25
|
+
// Core
|
|
26
|
+
Connection: require('./connection/connection'),
|
|
27
|
+
Server: require('./topologies/server'),
|
|
28
|
+
ReplSet: require('./topologies/replset'),
|
|
29
|
+
Mongos: require('./topologies/mongos'),
|
|
30
|
+
Logger: require('./connection/logger'),
|
|
31
|
+
Cursor: require('./cursor'),
|
|
32
|
+
ReadPreference: require('./topologies/read_preference'),
|
|
33
|
+
Sessions: require('./sessions'),
|
|
34
|
+
BSON: BSON,
|
|
35
|
+
EJSON: EJSON,
|
|
36
|
+
Topology: require('./sdam/topology'),
|
|
37
|
+
// Raw operations
|
|
38
|
+
Query: require('./connection/commands').Query,
|
|
39
|
+
// Auth mechanisms
|
|
40
|
+
MongoCredentials: require('./auth/mongo_credentials').MongoCredentials,
|
|
41
|
+
defaultAuthProviders: require('./auth/defaultAuthProviders').defaultAuthProviders,
|
|
42
|
+
MongoCR: require('./auth/mongocr'),
|
|
43
|
+
X509: require('./auth/x509'),
|
|
44
|
+
Plain: require('./auth/plain'),
|
|
45
|
+
GSSAPI: require('./auth/gssapi'),
|
|
46
|
+
ScramSHA1: require('./auth/scram').ScramSHA1,
|
|
47
|
+
ScramSHA256: require('./auth/scram').ScramSHA256,
|
|
48
|
+
// Utilities
|
|
49
|
+
parseConnectionString: require('./uri_parser')
|
|
50
|
+
};
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ServerDescription = require('./server_description').ServerDescription;
|
|
4
|
+
const calculateDurationInMs = require('../utils').calculateDurationInMs;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Published when server description changes, but does NOT include changes to the RTT.
|
|
8
|
+
*
|
|
9
|
+
* @property {Object} topologyId A unique identifier for the topology
|
|
10
|
+
* @property {ServerAddress} address The address (host/port pair) of the server
|
|
11
|
+
* @property {ServerDescription} previousDescription The previous server description
|
|
12
|
+
* @property {ServerDescription} newDescription The new server description
|
|
13
|
+
*/
|
|
14
|
+
class ServerDescriptionChangedEvent {
|
|
15
|
+
constructor(topologyId, address, previousDescription, newDescription) {
|
|
16
|
+
Object.assign(this, { topologyId, address, previousDescription, newDescription });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Published when server is initialized.
|
|
22
|
+
*
|
|
23
|
+
* @property {Object} topologyId A unique identifier for the topology
|
|
24
|
+
* @property {ServerAddress} address The address (host/port pair) of the server
|
|
25
|
+
*/
|
|
26
|
+
class ServerOpeningEvent {
|
|
27
|
+
constructor(topologyId, address) {
|
|
28
|
+
Object.assign(this, { topologyId, address });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Published when server is closed.
|
|
34
|
+
*
|
|
35
|
+
* @property {ServerAddress} address The address (host/port pair) of the server
|
|
36
|
+
* @property {Object} topologyId A unique identifier for the topology
|
|
37
|
+
*/
|
|
38
|
+
class ServerClosedEvent {
|
|
39
|
+
constructor(topologyId, address) {
|
|
40
|
+
Object.assign(this, { topologyId, address });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Published when topology description changes.
|
|
46
|
+
*
|
|
47
|
+
* @property {Object} topologyId
|
|
48
|
+
* @property {TopologyDescription} previousDescription The old topology description
|
|
49
|
+
* @property {TopologyDescription} newDescription The new topology description
|
|
50
|
+
*/
|
|
51
|
+
class TopologyDescriptionChangedEvent {
|
|
52
|
+
constructor(topologyId, previousDescription, newDescription) {
|
|
53
|
+
Object.assign(this, { topologyId, previousDescription, newDescription });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Published when topology is initialized.
|
|
59
|
+
*
|
|
60
|
+
* @param {Object} topologyId A unique identifier for the topology
|
|
61
|
+
*/
|
|
62
|
+
class TopologyOpeningEvent {
|
|
63
|
+
constructor(topologyId) {
|
|
64
|
+
Object.assign(this, { topologyId });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Published when topology is closed.
|
|
70
|
+
*
|
|
71
|
+
* @param {Object} topologyId A unique identifier for the topology
|
|
72
|
+
*/
|
|
73
|
+
class TopologyClosedEvent {
|
|
74
|
+
constructor(topologyId) {
|
|
75
|
+
Object.assign(this, { topologyId });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Fired when the server monitor’s ismaster command is started - immediately before
|
|
81
|
+
* the ismaster command is serialized into raw BSON and written to the socket.
|
|
82
|
+
*
|
|
83
|
+
* @property {Object} connectionId The connection id for the command
|
|
84
|
+
*/
|
|
85
|
+
class ServerHeartbeatStartedEvent {
|
|
86
|
+
constructor(connectionId) {
|
|
87
|
+
Object.assign(this, { connectionId });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Fired when the server monitor’s ismaster succeeds.
|
|
93
|
+
*
|
|
94
|
+
* @param {Number} duration The execution time of the event in ms
|
|
95
|
+
* @param {Object} reply The command reply
|
|
96
|
+
* @param {Object} connectionId The connection id for the command
|
|
97
|
+
*/
|
|
98
|
+
class ServerHeartbeatSucceededEvent {
|
|
99
|
+
constructor(duration, reply, connectionId) {
|
|
100
|
+
Object.assign(this, { duration, reply, connectionId });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Fired when the server monitor’s ismaster fails, either with an “ok: 0” or a socket exception.
|
|
106
|
+
*
|
|
107
|
+
* @param {Number} duration The execution time of the event in ms
|
|
108
|
+
* @param {MongoError|Object} failure The command failure
|
|
109
|
+
* @param {Object} connectionId The connection id for the command
|
|
110
|
+
*/
|
|
111
|
+
class ServerHeartbeatFailedEvent {
|
|
112
|
+
constructor(duration, failure, connectionId) {
|
|
113
|
+
Object.assign(this, { duration, failure, connectionId });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Performs a server check as described by the SDAM spec.
|
|
119
|
+
*
|
|
120
|
+
* NOTE: This method automatically reschedules itself, so that there is always an active
|
|
121
|
+
* monitoring process
|
|
122
|
+
*
|
|
123
|
+
* @param {Server} server The server to monitor
|
|
124
|
+
*/
|
|
125
|
+
function monitorServer(server, options) {
|
|
126
|
+
options = options || {};
|
|
127
|
+
const heartbeatFrequencyMS = options.heartbeatFrequencyMS || 10000;
|
|
128
|
+
|
|
129
|
+
if (options.initial === true) {
|
|
130
|
+
server.s.monitorId = setTimeout(() => monitorServer(server), heartbeatFrequencyMS);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// executes a single check of a server
|
|
135
|
+
const checkServer = callback => {
|
|
136
|
+
let start = process.hrtime();
|
|
137
|
+
|
|
138
|
+
// emit a signal indicating we have started the heartbeat
|
|
139
|
+
server.emit('serverHeartbeatStarted', new ServerHeartbeatStartedEvent(server.name));
|
|
140
|
+
|
|
141
|
+
// NOTE: legacy monitoring event
|
|
142
|
+
process.nextTick(() => server.emit('monitoring', server));
|
|
143
|
+
|
|
144
|
+
server.command(
|
|
145
|
+
'admin.$cmd',
|
|
146
|
+
{ ismaster: true },
|
|
147
|
+
{
|
|
148
|
+
monitoring: true,
|
|
149
|
+
socketTimeout: server.s.options.connectionTimeout || 2000
|
|
150
|
+
},
|
|
151
|
+
(err, result) => {
|
|
152
|
+
let duration = calculateDurationInMs(start);
|
|
153
|
+
|
|
154
|
+
if (err) {
|
|
155
|
+
server.emit(
|
|
156
|
+
'serverHeartbeatFailed',
|
|
157
|
+
new ServerHeartbeatFailedEvent(duration, err, server.name)
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
return callback(err, null);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const isMaster = result.result;
|
|
164
|
+
server.emit(
|
|
165
|
+
'serverHeartbeatSucceded',
|
|
166
|
+
new ServerHeartbeatSucceededEvent(duration, isMaster, server.name)
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
return callback(null, isMaster);
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const successHandler = isMaster => {
|
|
175
|
+
server.s.monitoring = false;
|
|
176
|
+
|
|
177
|
+
// emit an event indicating that our description has changed
|
|
178
|
+
server.emit('descriptionReceived', new ServerDescription(server.description.address, isMaster));
|
|
179
|
+
|
|
180
|
+
// schedule the next monitoring process
|
|
181
|
+
server.s.monitorId = setTimeout(() => monitorServer(server), heartbeatFrequencyMS);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// run the actual monitoring loop
|
|
185
|
+
server.s.monitoring = true;
|
|
186
|
+
checkServer((err, isMaster) => {
|
|
187
|
+
if (!err) {
|
|
188
|
+
successHandler(isMaster);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// According to the SDAM specification's "Network error during server check" section, if
|
|
193
|
+
// an ismaster call fails we reset the server's pool. If a server was once connected,
|
|
194
|
+
// change its type to `Unknown` only after retrying once.
|
|
195
|
+
server.s.pool.reset(() => {
|
|
196
|
+
// otherwise re-attempt monitoring once
|
|
197
|
+
checkServer((error, isMaster) => {
|
|
198
|
+
if (error) {
|
|
199
|
+
server.s.monitoring = false;
|
|
200
|
+
|
|
201
|
+
// we revert to an `Unknown` by emitting a default description with no isMaster
|
|
202
|
+
server.emit(
|
|
203
|
+
'descriptionReceived',
|
|
204
|
+
new ServerDescription(server.description.address, null, { error })
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
// we do not reschedule monitoring in this case
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
successHandler(isMaster);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
module.exports = {
|
|
218
|
+
ServerDescriptionChangedEvent,
|
|
219
|
+
ServerOpeningEvent,
|
|
220
|
+
ServerClosedEvent,
|
|
221
|
+
TopologyDescriptionChangedEvent,
|
|
222
|
+
TopologyOpeningEvent,
|
|
223
|
+
TopologyClosedEvent,
|
|
224
|
+
ServerHeartbeatStartedEvent,
|
|
225
|
+
ServerHeartbeatSucceededEvent,
|
|
226
|
+
ServerHeartbeatFailedEvent,
|
|
227
|
+
monitorServer
|
|
228
|
+
};
|