This is an automated email from the ASF dual-hosted git repository.
gyogal pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/livy.git
The following commit(s) were added to refs/heads/master by this push:
new 9e18a865 [LIVY-1061] Add livy.server.app-name-prefix for interactive
session YARN app names
9e18a865 is described below
commit 9e18a86524cdc7724946ba169f1769997153d3b8
Author: samuhasavak5 <[email protected]>
AuthorDate: Tue Jul 28 21:06:28 2026 +0530
[LIVY-1061] Add livy.server.app-name-prefix for interactive session YARN
app names
## What changes were proposed in this pull request?
This PR adds a new Livy server configuration property,
livy.server.app-name-prefix, to allow cluster administrators to customize the
default YARN application name for interactive Spark sessions.
Problem: When a client creates an interactive session via POST /sessions
without specifying a name, Livy sets spark.app.name to the hardcoded value
livy-session-<id>. In HA or multi-cluster environments, this makes it difficult
to distinguish Livy-managed applications in the YARN Resource Manager UI.
Solution:
Add LivyConf.SERVER_APP_NAME_PREFIX (livy.server.app-name-prefix, default:
livy-session)
Use the configured prefix when building the default spark.app.name in
InteractiveSession.create()
Document the new property in conf/livy.conf.template
Add unit tests for default and custom prefix behavior
Scope: Interactive sessions only. Batch sessions already support
per-request naming via the REST API name field and are unchanged.
Backward compatibility: When the property is unset, behavior remains
livy-session-<id>.
Example:
**livy.conf**
```
livy.server.app-name-prefix = my-cluster
```
Creating a session without a name yields YARN application name: my-cluster-3
JIRA: [LIVY-1061](https://issues.apache.org/jira/browse/LIVY-1061)
## How was this patch tested?
- Unit tests: Added tests in InteractiveSessionSpec for:
-Default prefix (livy-session) when config is not set
-Custom prefix (e.g. my-cluster) when livy.server.app-name-prefix is
configured
- Build: mvn package -Pspark3 -Pscala-2.12 — livy-server and dependent
modules built successfully
- Manual verification (recommended): Set livy.server.app-name-prefix in
livy.conf, create an interactive session without name, and confirm the YARN RM
UI shows <prefix>-<session-id>
No UI changes in this PR.
## Was this patch authored or co-authored using generative AI tooling?
Yes, this was co-authored using Cursor to help generate the new test cases.
---
conf/livy.conf.template | 4 ++++
.../src/main/scala/org/apache/livy/LivyConf.scala | 1 +
.../server/interactive/InteractiveSession.scala | 8 ++++++-
.../interactive/InteractiveSessionSpec.scala | 27 ++++++++++++++++++++++
4 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/conf/livy.conf.template b/conf/livy.conf.template
index 30a3a1f4..f489d76f 100644
--- a/conf/livy.conf.template
+++ b/conf/livy.conf.template
@@ -37,6 +37,10 @@
# What port to start the server on.
# livy.server.port = 8998
+# Prefix for YARN application names of interactive sessions when no name is
provided
+# in the session creation request. The application name becomes
<prefix>-<session-id>.
+# livy.server.app-name-prefix = livy-session
+
# What base path ui should work on. By default UI is mounted on "/".
# E.g.: livy.ui.basePath = /my_livy - result in mounting UI on /my_livy/
# livy.ui.basePath = ""
diff --git a/server/src/main/scala/org/apache/livy/LivyConf.scala
b/server/src/main/scala/org/apache/livy/LivyConf.scala
index 46c851f3..03bdf0fc 100644
--- a/server/src/main/scala/org/apache/livy/LivyConf.scala
+++ b/server/src/main/scala/org/apache/livy/LivyConf.scala
@@ -62,6 +62,7 @@ object LivyConf {
val SERVER_HOST = Entry("livy.server.host", "0.0.0.0")
val SERVER_PORT = Entry("livy.server.port", 8998)
val SERVER_BASE_PATH = Entry("livy.ui.basePath", "")
+ val SERVER_APP_NAME_PREFIX = Entry("livy.server.app-name-prefix",
"livy-session")
val UI_ENABLED = Entry("livy.ui.enabled", true)
diff --git
a/server/src/main/scala/org/apache/livy/server/interactive/InteractiveSession.scala
b/server/src/main/scala/org/apache/livy/server/interactive/InteractiveSession.scala
index e578326c..6af80133 100644
---
a/server/src/main/scala/org/apache/livy/server/interactive/InteractiveSession.scala
+++
b/server/src/main/scala/org/apache/livy/server/interactive/InteractiveSession.scala
@@ -78,6 +78,12 @@ object InteractiveSession extends Logging {
val RECOVERY_SESSION_TYPE = "interactive"
+ private[interactive] def defaultSparkAppName(sessionId: Int, livyConf:
LivyConf): String = {
+ val prefix =
Option(livyConf.get(LivyConf.SERVER_APP_NAME_PREFIX)).filter(_.nonEmpty)
+ .getOrElse("livy-session")
+ s"$prefix-$sessionId"
+ }
+
def create(
id: Int,
name: Option[String],
@@ -114,7 +120,7 @@ object InteractiveSession extends Logging {
opt.foreach { value => builderProperties.put(key, value) }
}
- builderProperties.getOrElseUpdate("spark.app.name", s"livy-session-$id")
+ builderProperties.getOrElseUpdate("spark.app.name",
defaultSparkAppName(id, livyConf))
info(s"Creating Interactive session $id: [owner: $owner, request:
$request]")
val builder = new LivyClientBuilder()
diff --git
a/server/src/test/scala/org/apache/livy/server/interactive/InteractiveSessionSpec.scala
b/server/src/test/scala/org/apache/livy/server/interactive/InteractiveSessionSpec.scala
index 72a2a31d..c19e671b 100644
---
a/server/src/test/scala/org/apache/livy/server/interactive/InteractiveSessionSpec.scala
+++
b/server/src/test/scala/org/apache/livy/server/interactive/InteractiveSessionSpec.scala
@@ -323,6 +323,33 @@ class InteractiveSessionSpec extends FunSpec
}
}
+ describe("default spark application name") {
+ it("should use livy-session prefix by default") {
+ val conf = new LivyConf(false)
+ InteractiveSession.defaultSparkAppName(42, conf) should
be("livy-session-42")
+ }
+
+ it("should use configured app name prefix") {
+ val conf = new LivyConf(false)
+ .set(LivyConf.SERVER_APP_NAME_PREFIX, "my-cluster")
+ InteractiveSession.defaultSparkAppName(3, conf) should be("my-cluster-3")
+ }
+
+ it("should fall back to livy-session when prefix is empty") {
+ val conf = new LivyConf(false)
+ .set(LivyConf.SERVER_APP_NAME_PREFIX, "")
+ InteractiveSession.defaultSparkAppName(5, conf) should
be("livy-session-5")
+ }
+
+ it("should not override user-provided spark.app.name") {
+ val conf = new LivyConf(false)
+ .set(LivyConf.SERVER_APP_NAME_PREFIX, "my-cluster")
+ val props = scala.collection.mutable.Map("spark.app.name" ->
"user-provided-name")
+ props.getOrElseUpdate("spark.app.name",
InteractiveSession.defaultSparkAppName(1, conf))
+ props("spark.app.name") should be("user-provided-name")
+ }
+ }
+
describe("InteractiveSession") {
it("should inherit the default YARN queue from LivyConf when request queue
is empty") {
val testLivyConf = new LivyConf()