private void initialFetchAndSchedule() {
    Runnable updater = () -> {
      try {
        fetchAndUpdateCache(false);
      } catch (Exception e) {
        logger.error("Exception occurred when fetching remote account data", e);
        accountServiceMetrics.fetchRemoteAccountErrorCount.inc();
      }
    };
    updater.run();

    // If fetching account metadata failed, no matter for what reason, we use the data from local backup file.
    // The local backup should be reasonably up-to-date.
    //
    // The caveat is that when a machine used to run ambry-frontend but then got decommissioned for a long time,
    // it will have a very old account metadata in the backup. If we reschedule ambry-frontend process in this particular
    // machine, and it fails to read the account metadata from AccountMetadataStore, then we would load stale data.
    //
    // One way to avoid this problem is to load latest account metadata, but not more than a month, from backup.

    // accountInfoMapRef's reference is empty doesn't mean that fetchAndUpdateCache failed, it would just be that there
    // is no account metadata for the time being. Theoretically local storage shouldn't have any backup files. So
    // backup.getLatestAccounts should return null. And in case we have a very old backup file just mentioned above, a threshold
    // would solve the problem.
    if (accountInfoMapRef.get().isEmpty() && config.enableServeFromBackup && !backupFileManager.isEmpty()) {
      long aMonthAgo = System.currentTimeMillis() / 1000 - TimeUnit.DAYS.toSeconds(30);
      Collection<Account> accounts = backupFileManager.getLatestAccounts(aMonthAgo);
      if (accounts != null) {
        AccountInfoMap newAccountInfoMap = new AccountInfoMap(accounts);
        accountInfoMapRef.set(newAccountInfoMap);

        // Notify accounts to consumers
        notifyAccountUpdateConsumers(accountInfoMapRef.get().getAccounts(), false);
      }
    }

    if (scheduler != null) {
      int initialDelay = new Random().nextInt(config.updaterPollingIntervalMs + 1);
      scheduler.scheduleAtFixedRate(updater, initialDelay, config.updaterPollingIntervalMs, TimeUnit.MILLISECONDS);
      logger.info(
          "Background account updater will fetch accounts from remote starting {} ms from now and repeat with interval={} ms",
          initialDelay, config.updaterPollingIntervalMs);
    }

    maybeSubscribeChangeTopic(true);
  }
This is a blocking call that would fetch the {@link Account} metadata and update the cache. Then schedule this logic
at a fixed rate.
ambry-account/src/main/java/com/github/ambry/account/HelixAccountService.java