in common/lib/plugins/failover2/failover2_plugin.ts [287:371]
private async getReaderFailoverConnection(failoverEndTimeMs: number): Promise<ReaderFailoverResult> {
// The roles in the host list may not be accurate, depending on whether the new topology has become available yet.
const hosts = this.pluginService.getHosts();
const readerCandidates = hosts.filter((x) => x.role === HostRole.READER);
const originalWriter: HostInfo = hosts.find((x) => x.role === HostRole.WRITER);
let isOriginalWriterStillWriter: boolean = false;
while (Date.now() < failoverEndTimeMs) {
// Try all the original readers.
const remainingReaders = readerCandidates;
while (remainingReaders.length > 0 && Date.now() < failoverEndTimeMs) {
let readerCandidate: HostInfo = null;
try {
readerCandidate = this.pluginService.getHostInfoByStrategy(HostRole.READER, this.failoverReaderHostSelectorStrategy, remainingReaders);
} catch (error) {
logger.info(Messages.get("Failover2.errorSelectingReaderHost", error.message));
}
if (readerCandidate === null) {
logger.info(Messages.get("Failover2.readerCandidateNull"));
} else {
try {
const candidateClient: ClientWrapper = await this.createConnectionForHost(readerCandidate);
const role: HostRole = await this.pluginService.getHostRole(candidateClient);
if (role === HostRole.READER || this.failoverMode !== FailoverMode.STRICT_READER) {
if (role !== readerCandidate.role) {
// Update readerCandidate to reflect correct role.
readerCandidate = this.pluginService.getHostInfoBuilder().copyFrom(readerCandidate).withRole(role).build();
}
return new ReaderFailoverResult(candidateClient, readerCandidate, true);
}
// Unable to fail over to readerCandidate, remove from remaining readers to try.
remainingReaders.splice(remainingReaders.indexOf(readerCandidate), 1);
await candidateClient.end();
if (role === HostRole.WRITER) {
// The readerCandidate is a writer, remove it from the list of reader candidates.
readerCandidates.splice(readerCandidates.indexOf(readerCandidate), 1);
} else {
logger.info(Messages.get("Failover2.strictReaderUnknownHostRole"));
}
} catch {
// Unable to connect to readerCandidate, remove from remaining readers to try.
remainingReaders.splice(remainingReaders.indexOf(readerCandidate), 1);
}
}
}
// Unable to connect to any of the original readers, try to connect to original writer.
if (originalWriter === null || Date.now() > failoverEndTimeMs) {
// No writer found in topology, or we have timed out.
continue;
}
if (this.failoverMode === FailoverMode.STRICT_READER && isOriginalWriterStillWriter) {
// Original writer has been verified, and it is not valid in strict-reader mode.
continue;
}
// Try the original writer, which may have been demoted.
try {
const candidateClient: ClientWrapper = await this.createConnectionForHost(originalWriter);
const role: HostRole = await this.pluginService.getHostRole(candidateClient);
if (role === HostRole.READER || this.failoverMode != FailoverMode.STRICT_READER) {
const updatedHostInfo: HostInfo = this.pluginService.getHostInfoBuilder().copyFrom(originalWriter).withRole(role).build();
return new ReaderFailoverResult(candidateClient, updatedHostInfo, true);
}
await candidateClient.end();
if (role === HostRole.WRITER) {
// Verify that writer has not been demoted, will not try to connect again.
isOriginalWriterStillWriter = true;
} else {
logger.info(Messages.get("Failover2.strictReaderUnknownHostRole"));
}
} catch {
logger.info(Messages.get("Failover.unableToConnectToReader"));
}
}
logger.error(Messages.get("Failover.timeoutError"));
throw new InternalQueryTimeoutError(Messages.get("Failover.timeoutError"));
}