You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kyuubi.apache.org by fe...@apache.org on 2022/09/01 04:28:33 UTC

[incubator-kyuubi] branch branch-1.6 updated: [KYUUBI #3315] Fast fail the kyuubi connection if the engine application has been terminated

This is an automated email from the ASF dual-hosted git repository.

feiwang pushed a commit to branch branch-1.6
in repository https://gitbox.apache.org/repos/asf/incubator-kyuubi.git


The following commit(s) were added to refs/heads/branch-1.6 by this push:
     new d1b6426bf [KYUUBI #3315] Fast fail the kyuubi connection if the engine application has been terminated
d1b6426bf is described below

commit d1b6426bf93bc6f5200950b9e2b4b763502c5e3e
Author: Fei Wang <fw...@ebay.com>
AuthorDate: Tue Aug 30 14:52:34 2022 +0800

    [KYUUBI #3315] Fast fail the kyuubi connection if the engine application has been terminated
    
    ### _Why are the changes needed?_
    
    We met the case that the LaunchEngine operation is succeed.
    
    But the spark engine met exception and terminated with SUCCESS state.
    
    And then the kyuubi connection stuck until reach the `kyuubi.session.engine.initialize.timeout`.
    
    The engine application terminated in 1.5 minutes and the engine init timeout is 10m.
    
    FYI:
    ![image](https://user-images.githubusercontent.com/6757692/186137705-615d3ae3-51cf-4afb-bbd9-9c1638c02181.png)
    
    So, we shall check the engine application state when waiting the engine initialization, and fast fail the connection if the application has been in terminated state.
    
    ### _How was this patch tested?_
    - [x] Add some test cases that check the changes thoroughly including negative and positive cases if possible
    
    - [ ] Add screenshots for manual tests if appropriate
    
    - [ ] [Run test](https://kyuubi.apache.org/docs/latest/develop_tools/testing.html#running-tests) locally before make a pull request
    
    Closes #3315 from turboFei/fast_fail_on_terminate.
    
    Closes #3315
    
    03333623 [Fei Wang] add comments
    f1632dbb [Fei Wang] fix ut
    4059a4fe [Fei Wang] combine the state
    33dc4a88 [Fei Wang] only check it for exit 0
    d5746af1 [Fei Wang] fix ut
    854f3e3b [Fei Wang] add metrics
    62001610 [Fei Wang] revert
    3fb1b630 [Fei Wang] remove engine ref check, meaning less
    d2c2c794 [Fei Wang] add ut
    ddafa24a [Fei Wang] fast fail the connection on engine termiante
    
    Authored-by: Fei Wang <fw...@ebay.com>
    Signed-off-by: Fei Wang <fw...@ebay.com>
---
 .../kyuubi/engine/ApplicationOperation.scala       | 16 ++++++++++++++++
 .../scala/org/apache/kyuubi/engine/EngineRef.scala | 22 ++++++++++++++++++++++
 .../kyuubi/operation/BatchJobSubmission.scala      | 14 ++------------
 .../org/apache/kyuubi/WithKyuubiServerOnYarn.scala | 17 +++++++++++++++++
 4 files changed, 57 insertions(+), 12 deletions(-)

diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/ApplicationOperation.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/ApplicationOperation.scala
index 9d8d4237d..93d495895 100644
--- a/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/ApplicationOperation.scala
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/engine/ApplicationOperation.scala
@@ -64,6 +64,22 @@ trait ApplicationOperation {
 object ApplicationState extends Enumeration {
   type ApplicationState = Value
   val PENDING, RUNNING, FINISHED, KILLED, FAILED, ZOMBIE, NOT_FOUND, UNKNOWN = Value
+
+  def isFailed(state: ApplicationState): Boolean = state match {
+    case FAILED => true
+    case KILLED => true
+    case _ => false
+  }
+
+  def isTerminated(state: ApplicationState): Boolean = {
+    state match {
+      case FAILED => true
+      case KILLED => true
+      case FINISHED => true
+      case NOT_FOUND => true
+      case _ => false
+    }
+  }
 }
 
 case class ApplicationInfo(
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 f3e2f3acd..10ffb87c9 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
@@ -205,6 +205,28 @@ private[kyuubi] class EngineRef(
             throw error
           }
         }
+
+        // even the submit process succeeds, the application might meet failure when initializing,
+        // check the engine application state from engine manager and fast fail on engine terminate
+        if (exitValue == Some(0)) {
+          Option(engineManager).foreach { engineMgr =>
+            engineMgr.getApplicationInfo(builder.clusterManager(), engineRefId).foreach { appInfo =>
+              if (ApplicationState.isTerminated(appInfo.state)) {
+                MetricsSystem.tracing { ms =>
+                  ms.incCount(MetricRegistry.name(ENGINE_FAIL, appUser))
+                  ms.incCount(MetricRegistry.name(ENGINE_FAIL, "ENGINE_TERMINATE"))
+                }
+                throw new KyuubiSQLException(
+                  s"""
+                     |The engine application has been terminated. Please check the engine log.
+                     |ApplicationInfo: ${appInfo.toMap.mkString("(\n", ",\n", "\n)")}
+                     |""".stripMargin,
+                  builder.getError)
+              }
+            }
+          }
+        }
+
         if (started + timeout <= System.currentTimeMillis()) {
           val killMessage = engineManager.killApplication(builder.clusterManager(), engineRefId)
           process.destroyForcibly()
diff --git a/kyuubi-server/src/main/scala/org/apache/kyuubi/operation/BatchJobSubmission.scala b/kyuubi-server/src/main/scala/org/apache/kyuubi/operation/BatchJobSubmission.scala
index c570c2d65..bcaca6237 100644
--- a/kyuubi-server/src/main/scala/org/apache/kyuubi/operation/BatchJobSubmission.scala
+++ b/kyuubi-server/src/main/scala/org/apache/kyuubi/operation/BatchJobSubmission.scala
@@ -339,20 +339,10 @@ class BatchJobSubmission(
 
 object BatchJobSubmission {
   def applicationFailed(applicationStatus: Option[ApplicationInfo]): Boolean = {
-    applicationStatus.map(_.state).exists {
-      case ApplicationState.FAILED => true
-      case ApplicationState.KILLED => true
-      case _ => false
-    }
+    applicationStatus.map(_.state).exists(ApplicationState.isFailed)
   }
 
   def applicationTerminated(applicationStatus: Option[ApplicationInfo]): Boolean = {
-    applicationStatus.map(_.state).exists {
-      case ApplicationState.FAILED => true
-      case ApplicationState.KILLED => true
-      case ApplicationState.FINISHED => true
-      case ApplicationState.NOT_FOUND => true
-      case _ => false
-    }
+    applicationStatus.map(_.state).exists(ApplicationState.isTerminated)
   }
 }
diff --git a/kyuubi-server/src/test/scala/org/apache/kyuubi/WithKyuubiServerOnYarn.scala b/kyuubi-server/src/test/scala/org/apache/kyuubi/WithKyuubiServerOnYarn.scala
index 514c89b17..cb55450ad 100644
--- a/kyuubi-server/src/test/scala/org/apache/kyuubi/WithKyuubiServerOnYarn.scala
+++ b/kyuubi-server/src/test/scala/org/apache/kyuubi/WithKyuubiServerOnYarn.scala
@@ -174,4 +174,21 @@ class KyuubiOperationYarnClusterSuite extends WithKyuubiServerOnYarn with HiveJD
       assert(batchJobSubmissionOp.getStatus.state === OperationState.ERROR)
     }
   }
+
+  test("fast fail the kyuubi connection on engine terminated") {
+    withSessionConf(Map.empty)(Map(
+      "spark.master" -> "yarn",
+      "spark.submit.deployMode" -> "cluster",
+      "spark.sql.defaultCatalog=spark_catalog" -> "spark_catalog",
+      "spark.sql.catalog.spark_catalog.type" -> "invalid_type",
+      "kyuubi.session.engine.initialize.timeout" -> "PT10m"))(Map.empty) {
+      val startTime = System.currentTimeMillis()
+      val exception = intercept[Exception] {
+        withJdbcStatement() { _ => }
+      }
+      val elapsedTime = System.currentTimeMillis() - startTime
+      assert(elapsedTime < 60 * 1000)
+      assert(exception.getMessage contains "The engine application has been terminated.")
+    }
+  }
 }