org.eclipse.hono.service.HealthCheckServer.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.hono.service.HealthCheckServer.java

Source

/**
 * Copyright (c) 2017 Bosch Software Innovations GmbH.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Bosch Software Innovations GmbH - initial creation
 */

package org.eclipse.hono.service;

import java.util.Objects;

import org.eclipse.hono.config.ApplicationConfigProperties;
import org.eclipse.hono.util.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.ext.healthchecks.HealthCheckHandler;
import io.vertx.ext.web.Router;

/**
 * Provides a HTTP server for health checks. Requires an instance of {@link ApplicationConfigProperties} for it's
 * configuration.
 * <p>
 * If {@code healthCheckPort} is not defined in the configuration, this implementation does nothing.
 * <p>
 * <b>Usage</b>
 * <ol>
 * <li>Invoke {@link #registerHealthCheckResources(HealthCheckProvider)} to register readiness and liveness checks.</li>
 * <li>Invoke {@link #start()} to start the server</li>
 * <li>Before shutdown: invoke {@link #stop()} for a graceful shutdown.</li>
 * </ol>
 */
public final class HealthCheckServer {

    private static final Logger LOG = LoggerFactory.getLogger(HealthCheckServer.class);

    private static final String URI_LIVENESS_PROBE = "/liveness";
    private static final String URI_READINESS_PROBE = "/readiness";

    private HttpServer server;

    private HealthCheckHandler readinessHandler;
    private HealthCheckHandler livenessHandler;

    private Vertx vertx;
    private ApplicationConfigProperties config;
    private Router router;

    /**
     * Create a new HealthCheckServer for the given Vertx and configuration.
     *
     * @param vertx The vertx instance.
     * @param config The application configuration instance.
     * @throws NullPointerException if vertx is {@code null}.
     * @throws NullPointerException if config is {@code null}.
     */
    public HealthCheckServer(Vertx vertx, ApplicationConfigProperties config) {
        this.vertx = Objects.requireNonNull(vertx);
        this.config = Objects.requireNonNull(config);

        prepareHealthCheck();
    }

    /**
     *
     * Configures router and healthCheckHandlers.
     *
     */
    private void prepareHealthCheck() {
        if (config.getHealthCheckPort() != Constants.PORT_UNCONFIGURED) {
            readinessHandler = HealthCheckHandler.create(vertx);
            livenessHandler = HealthCheckHandler.create(vertx);
            router = Router.router(vertx);
            LOG.debug("Health check prepared.");
        } else {
            LOG.info("No health check configured.");
        }
    }

    /**
     * Registers the readiness and liveness checks of the given service if health check is configured, otherwise does
     * nothing.
     * 
     * @param serviceInstance instance of the service which's checks should be registered.
     */
    public void registerHealthCheckResources(final HealthCheckProvider serviceInstance) {
        if (router != null) {
            serviceInstance.registerLivenessChecks(livenessHandler);
            serviceInstance.registerReadinessChecks(readinessHandler);
        } // else: health check port not configured.
    }

    /**
     * Starts the health check server if health check is configured, otherwise does nothing.
     *
     * @return a future indicating the output of the operation.
     */
    public Future<Void> start() {

        Future<Void> result = Future.future();
        if (router != null) {
            HttpServerOptions options = new HttpServerOptions().setPort(config.getHealthCheckPort())
                    .setHost(config.getHealthCheckBindAddress());
            server = vertx.createHttpServer(options);

            router.get(URI_READINESS_PROBE).handler(readinessHandler);
            router.get(URI_LIVENESS_PROBE).handler(livenessHandler);

            server.requestHandler(router::accept).listen(startAttempt -> {
                if (startAttempt.succeeded()) {
                    LOG.info("readiness probe available at http://{}:{}{}", options.getHost(), options.getPort(),
                            URI_READINESS_PROBE);
                    LOG.info("liveness probe available at http://{}:{}{}", options.getHost(), options.getPort(),
                            URI_LIVENESS_PROBE);
                    result.complete();
                } else {
                    LOG.warn("failed to start health checks HTTP server:", startAttempt.cause().getMessage());
                    result.fail(startAttempt.cause());
                }
            });

        } else { // health check port not configured
            result.complete();
        }
        return result;
    }

    /**
     * Closes the HTTP server if it exists.
     *
     * @return A Future indicating the outcome of the operation.
     */
    public Future<Void> stop() {

        Future<Void> result = Future.future();
        if (server != null) {
            server.close(result.completer());
        } else {
            result.complete();
        }
        return result;
    }

}