mirror of
https://github.com/mongodb/mongo.git
synced 2024-11-24 00:17:37 +01:00
82 lines
2.6 KiB
JavaScript
82 lines
2.6 KiB
JavaScript
/**
|
|
* A Promise-like interface for running a sequence of commands.
|
|
*
|
|
* If a network error occurs while running a command, then a reconnect is automatically
|
|
* attempted and the sequence will resume by sending the same command again. Any other errors
|
|
* that occur while running a command will cause the entire sequence of commands to abort.
|
|
*
|
|
* @param {Mongo} conn - a connection to the server
|
|
*/
|
|
|
|
function attemptReconnect(conn) {
|
|
try {
|
|
conn.adminCommand({ping: 1});
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export class CommandSequenceWithRetries {
|
|
constructor(conn) {
|
|
this.conn = conn;
|
|
this.steps = [];
|
|
}
|
|
|
|
then(phase, action) {
|
|
this.steps.push({phase, action});
|
|
return this;
|
|
}
|
|
|
|
execute() {
|
|
let i = 0;
|
|
let stepHadNetworkErrorAlready = false;
|
|
|
|
while (i < this.steps.length) {
|
|
try {
|
|
// Treat no explicit return statement inside the action function as returning
|
|
// {shouldStop: false} for syntactic convenience.
|
|
const result = this.steps[i].action(this.conn);
|
|
if (result !== undefined && result.shouldStop) {
|
|
return {
|
|
ok: 0,
|
|
msg: "giving up after " + this.steps[i].phase + ": " + result.reason
|
|
};
|
|
}
|
|
} catch (e) {
|
|
if (!isNetworkError(e)) {
|
|
throw e;
|
|
}
|
|
|
|
// We retry running the action function a second time after a network error
|
|
// because it is possible that the node is in the process of stepping down. We
|
|
// won't be able to reconnect to the node until it has finished closing all of
|
|
// its open connections.
|
|
if (stepHadNetworkErrorAlready) {
|
|
return {
|
|
ok: 0,
|
|
msg: "giving up after " + this.steps[i].phase +
|
|
" because we encountered multiple network errors"
|
|
};
|
|
}
|
|
|
|
if (!attemptReconnect(this.conn)) {
|
|
return {
|
|
ok: 0,
|
|
msg: "giving up after " + this.steps[i].phase +
|
|
" because attempting to reconnect failed"
|
|
};
|
|
}
|
|
|
|
stepHadNetworkErrorAlready = true;
|
|
continue;
|
|
}
|
|
|
|
++i;
|
|
stepHadNetworkErrorAlready = false;
|
|
}
|
|
|
|
return {ok: 1};
|
|
}
|
|
}
|