ServersChecker { public CompletableFuture<?> startAsync(Consumer<String> serverReadinessHandler) throws InfrastructureException { timer = new Timer("ServersChecker", true); List<ServerChecker> serverCheckers = getServerCheckers(); CompletableFuture<Void> firstNonAvailable = new CompletableFuture<>(); CompletableFuture[] checkTasks = serverCheckers .stream() .map(ServerChecker::getReportCompFuture) .map( compFut -> compFut .thenAccept(serverReadinessHandler) .exceptionally( e -> { timer.cancel(); firstNonAvailable.completeExceptionally(e); return null; })) .toArray(CompletableFuture[]::new); resultTimeoutSeconds = checkTasks.length * 180; CompletableFuture<Void> allAvailable = CompletableFuture.allOf(checkTasks); result = CompletableFuture.anyOf(allAvailable, firstNonAvailable); for (ServerChecker serverChecker : serverCheckers) { serverChecker.start(); } return result; } @Inject  ServersChecker(
      @Assisted RuntimeIdentity runtimeIdentity,
      @Assisted String machineName,
      @Assisted Map<String, ? extends Server> servers,
      MachineTokenProvider machineTokenProvider,
      @Named("che.workspace.server.ping_success_threshold") int serverPingSuccessThreshold,
      @Named("che.workspace.server.ping_interval_milliseconds") long serverPingInterval,
      @Named("che.workspace.server.liveness_probes") String[] livenessProbes); CompletableFuture<?> startAsync(Consumer<String> serverReadinessHandler); void checkOnce(Consumer<String> readyHandler); void await();  }
@Test(timeOut = 5000) public void shouldNotifyReadinessHandlerAboutEachServerReadiness() throws Exception { checker.startAsync(readinessHandler); verify(readinessHandler, after(500).never()).accept(anyString()); connectionChecker.getReportCompFuture().complete("test_ref"); verify(readinessHandler, times(3)).accept("test_ref"); }