private async getReaderFailoverConnection()

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"));
  }