/** * 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 * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * 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.alibaba.jstorm.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import com.alibaba.jstorm.cluster.StormConfig; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.jstorm.client.ConfigExtension; import backtype.storm.utils.Utils; /** * Launch one process for 3 purpose * 1. make the worker process become daemon process to ease Supervisor's pressure * 2. catch the exception and log the error message to worker's log when fail to launch worker, for example wrong jvm parameter * 3. create the log dir, avoid failing to create worker's gc log when dir doesn't exist * * @author longda */ public class ProcessLauncher { /** * Because ProcessLaucher will catch the exception when fail to start worker * it will use the same log as the worker's log * ProcessLauncher won't log until child process finishes. */ private static final Logger LOG = LoggerFactory.getLogger(ProcessLauncher.class); private static class LogWriter extends Thread { private Logger logger; private BufferedReader in; public LogWriter(InputStream in, Logger logger) { this.in = new BufferedReader(new InputStreamReader(in)); this.logger = logger; } public void run() { Logger logger = this.logger; BufferedReader in = this.in; String line; try { while ((line = in.readLine()) != null) { logger.info(line); } } catch (IOException e) { logger.error("Internal error", e); } finally { try { in.close(); } catch (IOException e) { logger.error("Internal error", e); } } } public void close() throws Exception { this.join(); } } private static class LauncherThread extends Thread { private String[] args; private int ret = 0; public LauncherThread(String[] args) { this.args = args; } public void run() { ProcessBuilder pb = new ProcessBuilder(args); Process p; try { p = pb.start(); } catch (IOException e1) { ret = -1; System.out.println("Failed to start " + JStormUtils.mk_list(args) + "\n" + e1); return; } try { ret = p.waitFor(); LOG.info(JStormUtils.getOutput(p.getErrorStream())); LOG.info(JStormUtils.getOutput(p.getInputStream())); LOG.info("!!!! Worker shutdown !!!!"); } catch (InterruptedException e) { ret = 0; System.out.println("Successfully start process"); } catch (Throwable e) { //ret = -1; LOG.error("Unknown exception" + e.getCause(), e); } finally { System.out.println("Begin to exit:" + ret); //JStormUtils.haltProcess(launcher.getResult()); System.exit(ret); } } public int getResult() { return ret; } } public static int getSleepSeconds() { Map<Object, Object> conf; try { conf = Utils.readStormConfig(); } catch (Exception e) { conf = new HashMap<>(); } return ConfigExtension.getProcessLauncherSleepSeconds(conf); } public static void main(String[] args) throws Exception { boolean isJstormOnYarn = System.getenv("jstorm.on.yarn").equals("1"); try { System.out.println("Environment:" + System.getenv()); System.out.println("Properties:" + System.getProperties()); int sleepSeconds = getSleepSeconds(); int ret = -1; try { System.out.println("start lanuncher, mode:" + isJstormOnYarn); if (System.getenv("REDIRECT") != null && System.getenv("REDIRECT").equals("true")) { ProcessBuilder pb = new ProcessBuilder(args); Process p = pb.start(); LogWriter err = null; LogWriter in = null; try { err = new LogWriter(p.getErrorStream(), LOG); err.start(); in = new LogWriter(p.getInputStream(), LOG); in.start(); ret = p.waitFor(); } finally { if (err != null) err.close(); if (in != null) in.close(); } } else if (isJstormOnYarn) { //can't quit process on yarn , we need keep cgroup inheritance relationship ProcessBuilder pb = new ProcessBuilder(args); Process p; p = pb.start(); ret = p.waitFor(); System.out.println(JStormUtils.getOutput(p.getErrorStream())); System.out.println(JStormUtils.getOutput(p.getInputStream())); } else { //when worker is dead, supervisor can kill ProcessLauncher right now //once worker start, worker will kill the processLauncher String workerId = System.getenv("jstorm.workerId"); if (StringUtils.isNotBlank(workerId)) { Map conf = Utils.readStormConfig(); StormConfig.validate_distributed_mode(conf); String pidDir = StormConfig.worker_pids_root(conf, workerId); JStormServerUtils.createPid(pidDir); } LauncherThread launcher = new LauncherThread(args); launcher.start(); Thread.sleep(sleepSeconds * 1000); launcher.interrupt(); ret = launcher.getResult(); } } finally { System.out.println("Begin to exit:" + ret); //JStormUtils.haltProcess(launcher.getResult()); JStormUtils.haltProcess(ret); } } catch (Exception e) { LOG.error("Error:", e); throw e; } } }