diff --git a/bin/stop-application.sh b/bin/stop-application.sh new file mode 100755 index 000000000..3fadde416 --- /dev/null +++ b/bin/stop-application.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# +# 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. +# + +if [[ $# < 1 ]] ; then + echo "USAGE: $0 " + exit 1 +fi + +if [[ -z ${HADOOP_HOME} ]]; then + echo "Error: HADOOP_HOME IS NOT SET! CANNOT PROCEED." + exit 1 +fi + +$HADOOP_HOME/bin/yarn application -kill $1 diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/EngineRef.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/EngineRef.scala index 20bb6dbf2..8abcdaf71 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/EngineRef.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/EngineRef.scala @@ -182,10 +182,11 @@ private[kyuubi] class EngineRef( } } if (started + timeout <= System.currentTimeMillis()) { + val killMessage = builder.killApplication() process.destroyForcibly() MetricsSystem.tracing(_.incCount(MetricRegistry.name(ENGINE_TIMEOUT, appUser))) throw KyuubiSQLException( - s"Timeout($timeout ms) to launched Spark with $builder", + s"Timeout($timeout ms) to launched Spark with $builder. $killMessage", builder.getError) } engineRef = getEngineByRefId(zkClient, engineSpace, engineRefId) diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/ProcBuilder.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/ProcBuilder.scala index 6e48170e7..62e325581 100644 --- a/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/ProcBuilder.scala +++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/ProcBuilder.scala @@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets import java.nio.file.{Files, Path} import scala.collection.JavaConverters._ +import scala.util.matching.Regex import org.apache.commons.lang3.StringUtils.containsIgnoreCase @@ -148,6 +149,29 @@ trait ProcBuilder { proc } + val YARN_APP_NAME_REGEX: Regex = "application_\\d+_\\d+".r + + def killApplication(line: String = lastRowOfLog): String = + YARN_APP_NAME_REGEX.findFirstIn(line) match { + case Some(appId) => + env.get(KyuubiConf.KYUUBI_HOME) match { + case Some(kyuubiHome) => + val pb = new ProcessBuilder("/bin/sh", s"$kyuubiHome/bin/stop-application.sh", appId) + pb.environment() + .putAll(env.asJava) + pb.redirectError(engineLog) + pb.redirectOutput(engineLog) + val process = pb.start() + process.waitFor() match { + case id if id != 0 => s"Failed to kill Application $appId, please kill it manually. " + case _ => s"Killed Application $appId successfully. " + } + case None => + s"KYUUBI_HOME is not set! Failed to kill Application $appId, please kill it manually." + } + case None => "" + } + def close(): Unit = { if (logCaptureThread != null) { logCaptureThread.interrupt()