This is an automated email from the ASF dual-hosted git repository.
chengpan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kyuubi.git
The following commit(s) were added to refs/heads/master by this push:
new 69e8e95429 [KYUUBI #7304] Fix NumberFormatException when parsing ISO
8601 duration for session idle timeout
69e8e95429 is described below
commit 69e8e95429b5bafb9eae1bff15cbaf1636756395
Author: anandnalya <[email protected]>
AuthorDate: Thu Jan 15 18:53:02 2026 +0800
[KYUUBI #7304] Fix NumberFormatException when parsing ISO 8601 duration for
session idle timeout
The `sessionIdleTimeoutThreshold` in `SparkSessionImpl` was using `.toLong`
directly on the config string value, which fails when the value is in ISO 8601
duration format (e.g., `PT40M`). This change uses `Duration.parse()` to
properly handle ISO 8601 duration format with fallback to plain milliseconds,
consistent with how `ConfigBuilder.timeConf` handles duration parsing elsewhere
in the codebase.
Closes #7304
### Why are the changes needed?
This fixes https://github.com/apache/kyuubi/issues/7304 which affects
v1.11.0 and v1.10.3
### How was this patch tested?
Tested with integration tests.
### Was this patch authored or co-authored using generative AI tooling?
Integration tests Generated-by: Claude Opus 4.5
Closes #7306 from anandnalya/fix/session-idle-timeout-duration-parsing.
Closes #7304
3bb8891e0 [anandnalya] [KYUUBI #7304] Fix NumberFormatException when
parsing ISO 8601 duration for session idle timeout
Authored-by: anandnalya <[email protected]>
Signed-off-by: Cheng Pan <[email protected]>
---
.../engine/spark/session/SparkSessionImpl.scala | 9 +-
.../spark/session/SessionIdleTimeoutSuite.scala | 99 ++++++++++++++++++++++
2 files changed, 105 insertions(+), 3 deletions(-)
diff --git
a/externals/kyuubi-spark-sql-engine/src/main/scala/org/apache/kyuubi/engine/spark/session/SparkSessionImpl.scala
b/externals/kyuubi-spark-sql-engine/src/main/scala/org/apache/kyuubi/engine/spark/session/SparkSessionImpl.scala
index 9498483be6..829fba2186 100644
---
a/externals/kyuubi-spark-sql-engine/src/main/scala/org/apache/kyuubi/engine/spark/session/SparkSessionImpl.scala
+++
b/externals/kyuubi-spark-sql-engine/src/main/scala/org/apache/kyuubi/engine/spark/session/SparkSessionImpl.scala
@@ -17,8 +17,11 @@
package org.apache.kyuubi.engine.spark.session
+import java.time.Duration
import java.util.concurrent.atomic.AtomicLong
+import scala.util.Try
+
import org.apache.commons.lang3.StringUtils
import org.apache.spark.sql.{AnalysisException, SparkSession}
import org.apache.spark.ui.SparkUIUtils.formatDuration
@@ -60,9 +63,9 @@ class SparkSessionImpl(
override val sessionIdleTimeoutThreshold: Long = {
conf.get(SESSION_IDLE_TIMEOUT.key)
- .map(_.toLong)
- .getOrElse(
- sessionManager.getConf.get(SESSION_IDLE_TIMEOUT))
+ .map(_.trim)
+ .map(v => Try(Duration.parse(v).toMillis).getOrElse(v.toLong))
+ .getOrElse(sessionManager.getConf.get(SESSION_IDLE_TIMEOUT))
}
private val sessionEvent = SessionEvent(this)
diff --git
a/externals/kyuubi-spark-sql-engine/src/test/scala/org/apache/kyuubi/engine/spark/session/SessionIdleTimeoutSuite.scala
b/externals/kyuubi-spark-sql-engine/src/test/scala/org/apache/kyuubi/engine/spark/session/SessionIdleTimeoutSuite.scala
new file mode 100644
index 0000000000..969c9ed28a
--- /dev/null
+++
b/externals/kyuubi-spark-sql-engine/src/test/scala/org/apache/kyuubi/engine/spark/session/SessionIdleTimeoutSuite.scala
@@ -0,0 +1,99 @@
+/*
+ * 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.kyuubi.engine.spark.session
+
+import java.sql.DriverManager
+
+import org.apache.kyuubi.config.KyuubiConf._
+import org.apache.kyuubi.engine.spark.WithSparkSQLEngine
+
+class SessionIdleTimeoutSuite extends WithSparkSQLEngine {
+
+ // Load JDBC driver
+ Class.forName("org.apache.kyuubi.jdbc.KyuubiHiveDriver")
+
+ override def withKyuubiConf: Map[String, String] = {
+ Map(
+ ENGINE_SHARE_LEVEL.key -> "SERVER",
+ ENGINE_SPARK_MAX_INITIAL_WAIT.key -> "0")
+ }
+
+ private def baseJdbcUrl: String =
+ s"jdbc:hive2://${engine.frontendServices.head.connectionUrl}/default"
+
+ test("KYUUBI #7304: session idle timeout supports ISO 8601 duration format")
{
+ // Test with ISO 8601 duration format (PT40M = 40 minutes = 2400000 ms)
+ val jdbcUrlWithIso8601Timeout =
+ s"$baseJdbcUrl;#${SESSION_IDLE_TIMEOUT.key}=PT40M"
+ val conn = DriverManager.getConnection(jdbcUrlWithIso8601Timeout,
"anonymous", "")
+ try {
+ val statement = conn.createStatement()
+ try {
+ val resultSet = statement.executeQuery("SELECT 1")
+ assert(resultSet.next())
+ assert(resultSet.getInt(1) == 1)
+ } finally {
+ statement.close()
+ }
+ } finally {
+ conn.close()
+ }
+ }
+
+ test("KYUUBI #7304: session idle timeout supports plain milliseconds") {
+ // Test with plain milliseconds (2400000 ms = 40 minutes)
+ val jdbcUrlWithMillisTimeout =
+ s"$baseJdbcUrl;#${SESSION_IDLE_TIMEOUT.key}=2400000"
+ val conn = DriverManager.getConnection(jdbcUrlWithMillisTimeout,
"anonymous", "")
+ try {
+ val statement = conn.createStatement()
+ try {
+ val resultSet = statement.executeQuery("SELECT 1")
+ assert(resultSet.next())
+ assert(resultSet.getInt(1) == 1)
+ } finally {
+ statement.close()
+ }
+ } finally {
+ conn.close()
+ }
+ }
+
+ test("KYUUBI #7304: session idle timeout supports various ISO 8601 formats")
{
+ // Test with different ISO 8601 duration formats
+ val testCases = Seq("PT1H", "PT30M", "PT1H30M", "PT90S")
+
+ testCases.foreach { durationStr =>
+ val jdbcUrlWithTimeout =
+ s"$baseJdbcUrl;#${SESSION_IDLE_TIMEOUT.key}=$durationStr"
+ val conn = DriverManager.getConnection(jdbcUrlWithTimeout, "anonymous",
"")
+ try {
+ val statement = conn.createStatement()
+ try {
+ val resultSet = statement.executeQuery("SELECT 1")
+ assert(resultSet.next())
+ assert(resultSet.getInt(1) == 1)
+ } finally {
+ statement.close()
+ }
+ } finally {
+ conn.close()
+ }
+ }
+ }
+}