eu.openanalytics.shinyproxy.ShinyProxyTestStrategy.java Source code

Java tutorial

Introduction

Here is the source code for eu.openanalytics.shinyproxy.ShinyProxyTestStrategy.java

Source

/**
 * ShinyProxy
 *
 * Copyright (C) 2016-2018 Open Analytics
 *
 * ===========================================================================
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the Apache License as published by
 * The Apache Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Apache License for more details.
 *
 * You should have received a copy of the Apache License
 * along with this program.  If not, see <http://www.apache.org/licenses/>
 */
package eu.openanalytics.shinyproxy;

import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.function.IntPredicate;

import javax.inject.Inject;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import eu.openanalytics.containerproxy.backend.strategy.IProxyTestStrategy;
import eu.openanalytics.containerproxy.model.runtime.Proxy;

/**
 * This component tests the responsiveness of Shiny containers by making an HTTP GET request to the container's published port (default 3838).
 * If this request does not receive a 200 (OK) response within a configured time limit, the container is considered to be unresponsive.
 */
@Component
@Primary
public class ShinyProxyTestStrategy implements IProxyTestStrategy {

    private Logger log = LogManager.getLogger(ShinyProxyTestStrategy.class);

    @Inject
    private Environment environment;

    @Override
    public boolean testProxy(Proxy proxy) {

        int totalWaitMs = Integer.parseInt(environment.getProperty("proxy.container-wait-time", "20000"));
        int waitMs = Math.min(2000, totalWaitMs);
        int maxTries = totalWaitMs / waitMs;
        int timeoutMs = Integer.parseInt(environment.getProperty("proxy.container-wait-timeout", "5000"));

        if (proxy.getTargets().isEmpty())
            return false;
        URI targetURI = proxy.getTargets().values().iterator().next();

        return retry(i -> {
            try {
                URL testURL = new URL(targetURI.toString());
                HttpURLConnection connection = ((HttpURLConnection) testURL.openConnection());
                connection.setConnectTimeout(timeoutMs);
                int responseCode = connection.getResponseCode();
                if (responseCode == 200)
                    return true;
            } catch (Exception e) {
                if (i > 1 && log != null)
                    log.warn(String.format("Container unresponsive, trying again (%d/%d): %s", i, maxTries,
                            targetURI));
            }
            return false;
        }, maxTries, waitMs, false);
    }

    private static boolean retry(IntPredicate job, int tries, int waitTime, boolean retryOnException) {
        boolean retVal = false;
        RuntimeException exception = null;
        for (int currentTry = 1; currentTry <= tries; currentTry++) {
            try {
                if (job.test(currentTry)) {
                    retVal = true;
                    exception = null;
                    break;
                }
            } catch (RuntimeException e) {
                if (retryOnException)
                    exception = e;
                else
                    throw e;
            }
            try {
                Thread.sleep(waitTime);
            } catch (InterruptedException ignore) {
            }
        }
        if (exception == null)
            return retVal;
        else
            throw exception;
    }
}