/*
 * Copyright 2015 LINE Corporation
 *
 * LINE Corporation licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package com.linecorp.armeria.server.healthcheck;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;

import java.time.Duration;
import java.util.concurrent.CompletionStage;
import java.util.function.Supplier;

import com.linecorp.armeria.common.CommonPools;
import com.linecorp.armeria.common.annotation.UnstableApi;
import com.linecorp.armeria.server.Server;

import io.netty.util.concurrent.EventExecutor;

/**
 * Determines whether the {@link Server} is healthy. All registered {@link HealthChecker}s must return
 * {@code true} for the {@link Server} to be considered healthy.
 */
@FunctionalInterface
public interface HealthChecker {

    /**
     * Returns a newly created {@link HealthChecker} that invokes the specified health checker
     * repetitively on an arbitrary {@link EventExecutor} from {@link CommonPools#workerGroup()}.
     *
     * @param healthChecker A {@link Supplier} that performs a health check asynchronously and
     *                      returns a future that will complete with a {@link HealthCheckStatus}.
     *                      {@link HealthCheckStatus#ttlMillis()} determines the delay before the
     *                      next health check. If the future completed exceptionally, the specified
     *                      {@code fallbackTtl} will be used instead to determine the delay.
     *                      {@link Supplier} should avoid returning null or throwing exception.
     *                      The {@link CompletionStage} from {@link Supplier} should avoid completing
     *                      with null result or failing.
     * @param fallbackTtl   The amount of delay between each health check if the previous health
     *                      check failed unexpectedly so it's not possible to determine how long
     *                      we have to wait until the next health check.
     *
     * @see #of(Supplier, Duration, EventExecutor)
     */
    @UnstableApi
    static HealthChecker of(Supplier<? extends CompletionStage<HealthCheckStatus>> healthChecker,
                            Duration fallbackTtl) {
        return of(healthChecker, fallbackTtl, CommonPools.workerGroup().next());
    }

    /**
     * Returns a newly created {@link HealthChecker} that invokes the specified health checker
     * repetitively on the specified {@link EventExecutor}.
     *
     * @param healthChecker A {@link Supplier} that performs a health check asynchronously and
     *                      returns a future that will complete with a {@link HealthCheckStatus}.
     *                      {@link HealthCheckStatus#ttlMillis()} determines the delay before the
     *                      next health check. If the future completed exceptionally, the specified
     *                      {@code fallbackTtl} will be used instead to determine the delay.
     *                      {@link Supplier} should avoid returning null or throwing exception.
     *                      The {@link CompletionStage} from {@link Supplier} should avoid completing
     *                      with null result or failing.
     * @param fallbackTtl   The amount of delay between each health check if the previous health
     *                      check failed unexpectedly so it's not possible to determine how long
     *                      we have to wait until the next health check.
     * @param eventExecutor The {@link EventExecutor} that will invoke the specified {@code healthChecker}.
     */
    @UnstableApi
    static HealthChecker of(Supplier<? extends CompletionStage<HealthCheckStatus>> healthChecker,
                            Duration fallbackTtl, EventExecutor eventExecutor) {
        requireNonNull(fallbackTtl, "fallbackTtl");
        checkArgument(!fallbackTtl.isNegative() && !fallbackTtl.isZero(), "fallbackTtl: %s (expected: > 0)",
                      fallbackTtl);
        return new ScheduledHealthChecker(requireNonNull(healthChecker, "healthChecker"),
                                          fallbackTtl,
                                          requireNonNull(eventExecutor, "eventExecutor"));
    }

    /**
     * Returns {@code true} if and only if the {@link Server} is healthy.
     */
    boolean isHealthy();
}

@@ -1370,32 +1370,42 @@
  created %7B@link 
+Listenable
 HealthChecker%7D t
@@ -1443,32 +1443,41 @@
 h checker%0A     *
+ function
  repetitively on
@@ -2651,32 +2651,42 @@
 eApi%0A    static 
+Listenable
 HealthChecker of
@@ -2748,32 +2748,42 @@
  healthChecker,%0A
+          
                 
@@ -2944,32 +2944,42 @@
  created %7B@link 
+Listenable
 HealthChecker%7D t
@@ -3025,16 +3025,25 @@
 r%0A     *
+ function
  repetit
@@ -4245,16 +4245,26 @@
  static 
+Listenable
 HealthCh
@@ -4334,32 +4334,42 @@
  healthChecker,%0A
+          
                 

Return `ListenableHealthChecker` instead of `HealthChecker` for `HealthChecker.of()` (#4017)