You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@livy.apache.org by js...@apache.org on 2019/08/09 06:52:05 UTC

[incubator-livy] branch master updated: [LIVY-547][SERVER] Livy kills session after livy.server.session.timeout even if the session is active

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

jshao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-livy.git


The following commit(s) were added to refs/heads/master by this push:
     new e7f23e0  [LIVY-547][SERVER] Livy kills session after livy.server.session.timeout even if the session is active
e7f23e0 is described below

commit e7f23e06606ff79aec1c22e79a96f959cb89a8be
Author: Shanyu Zhao <sh...@microsoft.com>
AuthorDate: Fri Aug 9 14:51:08 2019 +0800

    [LIVY-547][SERVER] Livy kills session after livy.server.session.timeout even if the session is active
    
    ## What changes were proposed in this pull request?
    Add a new configuration:
      livy.server.session.timeout-check.skip-busy
    To indicate whether or not to skip timeout check for a busy session. It defaults to false for
    backward compatibility.
    
    https://issues.apache.org/jira/browse/LIVY-547
    
    ## How was this patch tested?
    
    Manually tested the configuration.
    
    Author: Shanyu Zhao <sh...@microsoft.com>
    
    Closes #190 from shanyu/shanyu-547.
---
 conf/livy.conf.template                              |  6 +++++-
 server/src/main/scala/org/apache/livy/LivyConf.scala |  3 +++
 .../org/apache/livy/sessions/SessionManager.scala    |  4 ++++
 .../scala/org/apache/livy/sessions/MockSession.scala |  3 ++-
 .../apache/livy/sessions/SessionManagerSpec.scala    | 20 ++++++++++++++++++--
 5 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/conf/livy.conf.template b/conf/livy.conf.template
index 2590e87..de7c248 100644
--- a/conf/livy.conf.template
+++ b/conf/livy.conf.template
@@ -50,8 +50,12 @@
 
 # Enabled to check whether timeout Livy sessions should be stopped.
 # livy.server.session.timeout-check = true
+#
+# Whether or not to skip timeout check for a busy session
+# livy.server.session.timeout-check.skip-busy = false
 
-# Time in milliseconds on how long Livy will wait before timing out an idle session.
+# Time in milliseconds on how long Livy will wait before timing out an inactive session.
+# Note that the inactive session could be busy running jobs.
 # livy.server.session.timeout = 1h
 #
 # How long a finished session state should be kept in LivyServer for query.
diff --git a/server/src/main/scala/org/apache/livy/LivyConf.scala b/server/src/main/scala/org/apache/livy/LivyConf.scala
index 32b3522..dec8e4a 100644
--- a/server/src/main/scala/org/apache/livy/LivyConf.scala
+++ b/server/src/main/scala/org/apache/livy/LivyConf.scala
@@ -216,6 +216,9 @@ object LivyConf {
   // Whether session timeout should be checked, by default it will be checked, which means inactive
   // session will be stopped after "livy.server.session.timeout"
   val SESSION_TIMEOUT_CHECK = Entry("livy.server.session.timeout-check", true)
+  // Whether session timeout check should skip busy sessions, if set to true, then busy sessions
+  // that have jobs running will never timeout.
+  val SESSION_TIMEOUT_CHECK_SKIP_BUSY = Entry("livy.server.session.timeout-check.skip-busy", false)
   // How long will an inactive session be gc-ed.
   val SESSION_TIMEOUT = Entry("livy.server.session.timeout", "1h")
   // How long a finished session state will be kept in memory
diff --git a/server/src/main/scala/org/apache/livy/sessions/SessionManager.scala b/server/src/main/scala/org/apache/livy/sessions/SessionManager.scala
index a63cab3..f8f98a2 100644
--- a/server/src/main/scala/org/apache/livy/sessions/SessionManager.scala
+++ b/server/src/main/scala/org/apache/livy/sessions/SessionManager.scala
@@ -77,6 +77,8 @@ class SessionManager[S <: Session, R <: RecoveryMetadata : ClassTag](
 
 
   private[this] final val sessionTimeoutCheck = livyConf.getBoolean(LivyConf.SESSION_TIMEOUT_CHECK)
+  private[this] final val sessionTimeoutCheckSkipBusy =
+    livyConf.getBoolean(LivyConf.SESSION_TIMEOUT_CHECK_SKIP_BUSY)
   private[this] final val sessionTimeout =
     TimeUnit.MILLISECONDS.toNanos(livyConf.getTimeAsMs(LivyConf.SESSION_TIMEOUT))
   private[this] final val sessionStateRetainedInSec =
@@ -153,6 +155,8 @@ class SessionManager[S <: Session, R <: RecoveryMetadata : ClassTag](
         case _ =>
           if (!sessionTimeoutCheck) {
             false
+          } else if (session.state == SessionState.Busy && sessionTimeoutCheckSkipBusy) {
+            false
           } else if (session.isInstanceOf[BatchSession]) {
             false
           } else {
diff --git a/server/src/test/scala/org/apache/livy/sessions/MockSession.scala b/server/src/test/scala/org/apache/livy/sessions/MockSession.scala
index 3d0cc26..ddcbd4b 100644
--- a/server/src/test/scala/org/apache/livy/sessions/MockSession.scala
+++ b/server/src/test/scala/org/apache/livy/sessions/MockSession.scala
@@ -31,7 +31,8 @@ class MockSession(id: Int, owner: String, conf: LivyConf, name: Option[String] =
 
   override def logLines(): IndexedSeq[String] = IndexedSeq()
 
-  override def state: SessionState = SessionState.Idle
+  var serverState: SessionState = SessionState.Idle
+  override def state: SessionState = serverState
 
   override def recoveryMetadata: RecoveryMetadata = RecoveryMetadata(0)
 }
diff --git a/server/src/test/scala/org/apache/livy/sessions/SessionManagerSpec.scala b/server/src/test/scala/org/apache/livy/sessions/SessionManagerSpec.scala
index 193d95b..a5e9ffa 100644
--- a/server/src/test/scala/org/apache/livy/sessions/SessionManagerSpec.scala
+++ b/server/src/test/scala/org/apache/livy/sessions/SessionManagerSpec.scala
@@ -36,8 +36,8 @@ import org.apache.livy.sessions.Session.RecoveryMetadata
 class SessionManagerSpec extends FunSpec with Matchers with LivyBaseUnitTestSuite {
   implicit def executor: ExecutionContext = ExecutionContext.global
 
-  private def createSessionManager(): (LivyConf, SessionManager[MockSession, RecoveryMetadata]) = {
-    val livyConf = new LivyConf()
+  private def createSessionManager(livyConf: LivyConf = new LivyConf())
+    : (LivyConf, SessionManager[MockSession, RecoveryMetadata]) = {
     livyConf.set(LivyConf.SESSION_TIMEOUT, "100ms")
     val manager = new SessionManager[MockSession, RecoveryMetadata](
       livyConf,
@@ -59,6 +59,22 @@ class SessionManagerSpec extends FunSpec with Matchers with LivyBaseUnitTestSuit
       }
     }
 
+    it("should not garbage collect busy sessions if skip-busy configured") {
+      val lc = new LivyConf()
+      lc.set(LivyConf.SESSION_TIMEOUT_CHECK_SKIP_BUSY, true)
+      val (livyConf, manager) = createSessionManager(lc)
+      val session1 = manager.register(new MockSession(manager.nextId(), null, livyConf))
+      val session2 = manager.register(new MockSession(manager.nextId(), null, livyConf))
+      manager.get(session1.id).isDefined should be(true)
+      manager.get(session2.id).isDefined should be(true)
+      session2.serverState = SessionState.Busy
+      eventually(timeout(5 seconds), interval(100 millis)) {
+        Await.result(manager.collectGarbage(), Duration.Inf)
+        (manager.get(session1.id).isDefined, manager.get(session2.id).isDefined) should
+          be (false, true)
+      }
+    }
+
     it("should create sessions with names") {
       val (livyConf, manager) = createSessionManager()
       val name = "Mock-session"