All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.oozie.action.hadoop.LauncherAMCallbackNotifier Maven / Gradle / Ivy

There is a newer version: 5.2.1
Show newest version
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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
 *
 *      http://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 org.apache.oozie.action.hadoop;

import org.apache.hadoop.conf.Configuration;
import org.apache.oozie.action.hadoop.LauncherAM.OozieActionResult;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;

// Adapted from org.apache.hadoop.mapreduce.v2.app.JobEndNotifier
/**
 * This call sends back an HTTP GET callback to the configured URL.  It is meant for the {@link LauncherAM} to notify the
 * Oozie Server that it has finished.
 */
public class LauncherAMCallbackNotifier {
    private static final String OOZIE_LAUNCHER_CALLBACK = "oozie.launcher.callback.";
    private static final int OOZIE_LAUNCHER_CALLBACK_RETRY_INTERVAL_MAX = 5000;

    public static final String OOZIE_LAUNCHER_CALLBACK_RETRY_ATTEMPTS = OOZIE_LAUNCHER_CALLBACK + "retry.attempts";
    public static final String OOZIE_LAUNCHER_CALLBACK_RETRY_INTERVAL = OOZIE_LAUNCHER_CALLBACK + "retry.interval";
    public static final String OOZIE_LAUNCHER_CALLBACK_MAX_ATTEMPTS = OOZIE_LAUNCHER_CALLBACK + "max.attempts";
    public static final String OOZIE_LAUNCHER_CALLBACK_TIMEOUT = OOZIE_LAUNCHER_CALLBACK + "timeout";
    public static final String OOZIE_LAUNCHER_CALLBACK_URL = OOZIE_LAUNCHER_CALLBACK + "url";
    public static final String OOZIE_LAUNCHER_CALLBACK_PROXY = OOZIE_LAUNCHER_CALLBACK + "proxy";
    public static final String OOZIE_LAUNCHER_CALLBACK_JOBSTATUS_TOKEN = "$jobStatus";

    protected String userUrl;
    protected String proxyConf;
    protected int numTries; //Number of tries to attempt notification
    protected int waitInterval; //Time (ms) to wait between retrying notification
    protected int timeout; // Timeout (ms) on the connection and notification
    protected URL urlToNotify; //URL to notify read from the config
    protected Proxy proxyToUse = Proxy.NO_PROXY; //Proxy to use for notification


    /**
     * Parse the URL that needs to be notified of the end of the job, along
     * with the number of retries in case of failure, the amount of time to
     * wait between retries and proxy settings
     * @param conf the configuration
     */
    public LauncherAMCallbackNotifier(Configuration conf) {
        numTries = Math.min(conf.getInt(OOZIE_LAUNCHER_CALLBACK_RETRY_ATTEMPTS, 0) + 1,
                conf.getInt(OOZIE_LAUNCHER_CALLBACK_MAX_ATTEMPTS, 1));

        waitInterval = Math.min(conf.getInt(OOZIE_LAUNCHER_CALLBACK_RETRY_INTERVAL, OOZIE_LAUNCHER_CALLBACK_RETRY_INTERVAL_MAX),
                OOZIE_LAUNCHER_CALLBACK_RETRY_INTERVAL_MAX);
        waitInterval = (waitInterval < 0) ? OOZIE_LAUNCHER_CALLBACK_RETRY_INTERVAL_MAX : waitInterval;

        timeout = conf.getInt(OOZIE_LAUNCHER_CALLBACK_TIMEOUT, OOZIE_LAUNCHER_CALLBACK_RETRY_INTERVAL_MAX);

        userUrl = conf.get(OOZIE_LAUNCHER_CALLBACK_URL);

        proxyConf = conf.get(OOZIE_LAUNCHER_CALLBACK_PROXY);

        //Configure the proxy to use if its set. It should be set like
        //proxyType@proxyHostname:port
        if(proxyConf != null && !proxyConf.equals("") &&
                proxyConf.lastIndexOf(":") != -1) {
            int typeIndex = proxyConf.indexOf("@");
            Proxy.Type proxyType = Proxy.Type.HTTP;
            if(typeIndex != -1 &&
                    proxyConf.substring(0, typeIndex).compareToIgnoreCase("socks") == 0) {
                proxyType = Proxy.Type.SOCKS;
            }
            String hostname = proxyConf.substring(typeIndex + 1,
                    proxyConf.lastIndexOf(":"));
            String portConf = proxyConf.substring(proxyConf.lastIndexOf(":") + 1);
            try {
                int port = Integer.parseInt(portConf);
                proxyToUse = new Proxy(proxyType,
                        new InetSocketAddress(hostname, port));
                System.out.println("Callback notification using proxy type \"" + proxyType +
                        "\" hostname \"" + hostname + "\" and port \"" + port + "\"");
            } catch(NumberFormatException nfe) {
                System.err.println("Callback notification couldn't parse configured proxy's port "
                        + portConf + ". Not going to use a proxy");
            }
        }

    }

    /**
     * Notify the URL just once. Use best effort.
     * @return true in case URL is notified successfully.
     */
    protected boolean notifyURLOnce() {
        boolean success = false;
        HttpURLConnection conn = null;
        try {
            System.out.println("Callback notification trying " + urlToNotify);
            conn = (HttpURLConnection) urlToNotify.openConnection(proxyToUse);
            conn.setConnectTimeout(timeout);
            conn.setReadTimeout(timeout);
            conn.setAllowUserInteraction(false);
            if(conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
                System.err.println("Callback notification to " + urlToNotify +" failed with code: "
                        + conn.getResponseCode() + " and message \"" + conn.getResponseMessage()
                        +"\"");
            }
            else {
                success = true;
                System.out.println("Callback notification to " + urlToNotify + " succeeded");
            }
        } catch(IOException ioe) {
            System.err.println("Callback notification to " + urlToNotify + " failed");
            ioe.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return success;
    }

    /**
     * Notify a server of the completion of a submitted job.
     * @param actionResult The Action Result (failed/succeeded/running)
     *
     * @throws InterruptedException in case of interruption
     */
    public void notifyURL(OozieActionResult actionResult) throws InterruptedException {
        // Do we need job-end notification?
        if (userUrl == null) {
            System.out.println("Callback notification URL not set, skipping.");
            return;
        }

        //Do string replacements for final status
        if (userUrl.contains(OOZIE_LAUNCHER_CALLBACK_JOBSTATUS_TOKEN)) {
            userUrl = userUrl.replace(OOZIE_LAUNCHER_CALLBACK_JOBSTATUS_TOKEN, actionResult.toString());
        }

        // Create the URL, ensure sanity
        try {
            urlToNotify = new URL(userUrl);
        } catch (MalformedURLException mue) {
            System.err.println("Callback notification couldn't parse " + userUrl);
            mue.printStackTrace();
            return;
        }

        // Send notification
        boolean success = false;
        while (numTries-- > 0 && !success) {
            System.out.println("Callback notification attempts left " + numTries);
            success = notifyURLOnce();
            if (!success) {
                Thread.sleep(waitInterval);
            }
        }
        if (!success) {
            System.err.println("Callback notification failed to notify : " + urlToNotify);
        } else {
            System.out.println("Callback notification succeeded");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy