Skip to content

Commit 44f654e

Browse files
committed
SPARK-1202: Improvements to task killing in the UI.
1. Adds a separate endpoint for the killing logic that is outside of a page. 2. Narrows the scope of the killingEnabled tracking. 3. Some style improvements. Author: Patrick Wendell <[email protected]> Closes #386 from pwendell/kill-link and squashes the following commits: 8efe02b [Patrick Wendell] Improvements to task killing in the UI.
1 parent 7b4203a commit 44f654e

File tree

6 files changed

+38
-22
lines changed

6 files changed

+38
-22
lines changed

core/src/main/resources/org/apache/spark/ui/static/webui.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,12 @@ table.sortable thead {
7878
background-repeat: repeat-x;
7979
filter: progid:dximagetransform.microsoft.gradient(startColorstr='#FFA4EDFF', endColorstr='#FF94DDFF', GradientType=0);
8080
}
81+
82+
span.kill-link {
83+
margin-right: 2px;
84+
color: gray;
85+
}
86+
87+
span.kill-link a {
88+
color: gray;
89+
}

core/src/main/scala/org/apache/spark/ui/JettyUtils.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,12 @@ private[spark] object JettyUtils extends Logging {
104104
def createRedirectHandler(
105105
srcPath: String,
106106
destPath: String,
107+
beforeRedirect: HttpServletRequest => Unit = x => (),
107108
basePath: String = ""): ServletContextHandler = {
108109
val prefixedDestPath = attachPrefix(basePath, destPath)
109110
val servlet = new HttpServlet {
110111
override def doGet(request: HttpServletRequest, response: HttpServletResponse) {
112+
beforeRedirect(request)
111113
// Make sure we don't end up with "//" in the middle
112114
val newUrl = new URL(new URL(request.getRequestURL.toString), prefixedDestPath).toString
113115
response.sendRedirect(newUrl)

core/src/main/scala/org/apache/spark/ui/SparkUI.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import org.apache.spark.util.Utils
3232
/** Top level user interface for Spark */
3333
private[spark] class SparkUI(
3434
val sc: SparkContext,
35-
conf: SparkConf,
35+
val conf: SparkConf,
3636
val listenerBus: SparkListenerBus,
3737
var appName: String,
3838
val basePath: String = "")
@@ -46,7 +46,6 @@ private[spark] class SparkUI(
4646
val live = sc != null
4747

4848
val securityManager = if (live) sc.env.securityManager else new SecurityManager(conf)
49-
val killEnabled = conf.getBoolean("spark.ui.killEnabled", true)
5049

5150
private val localHost = Utils.localHostName()
5251
private val publicHost = Option(System.getenv("SPARK_PUBLIC_DNS")).getOrElse(localHost)
@@ -70,7 +69,7 @@ private[spark] class SparkUI(
7069
metricsServletHandlers ++
7170
Seq[ServletContextHandler] (
7271
createStaticHandler(SparkUI.STATIC_RESOURCE_DIR, "/static"),
73-
createRedirectHandler("/", "/stages", basePath)
72+
createRedirectHandler("/", "/stages", basePath = basePath)
7473
)
7574
}
7675

core/src/main/scala/org/apache/spark/ui/jobs/IndexPage.scala

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ private[ui] class IndexPage(parent: JobProgressUI) {
3232
private val sc = parent.sc
3333
private lazy val listener = parent.listener
3434
private lazy val isFairScheduler = parent.isFairScheduler
35-
private val killEnabled = parent.killEnabled
3635

3736
private def appName = parent.appName
3837

@@ -43,16 +42,6 @@ private[ui] class IndexPage(parent: JobProgressUI) {
4342
val failedStages = listener.failedStages.reverse.toSeq
4443
val now = System.currentTimeMillis()
4544

46-
if (killEnabled) {
47-
val killFlag = Option(request.getParameter("terminate")).getOrElse("false").toBoolean
48-
val stageId = Option(request.getParameter("id")).getOrElse("-1").toInt
49-
50-
if (stageId >= 0 && killFlag && listener.activeStages.contains(stageId)) {
51-
sc.cancelStage(stageId)
52-
}
53-
}
54-
55-
5645
val activeStagesTable =
5746
new StageTable(activeStages.sortBy(_.submissionTime).reverse, parent, parent.killEnabled)
5847
val completedStagesTable =

core/src/main/scala/org/apache/spark/ui/jobs/JobProgressUI.scala

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ private[ui] class JobProgressUI(parent: SparkUI) {
3232
val basePath = parent.basePath
3333
val live = parent.live
3434
val sc = parent.sc
35-
val killEnabled = parent.killEnabled
35+
val killEnabled = parent.conf.getBoolean("spark.ui.killEnabled", true)
3636

3737
lazy val listener = _listener.get
3838
lazy val isFairScheduler = listener.schedulingMode.exists(_ == SchedulingMode.FAIR)
@@ -51,7 +51,22 @@ private[ui] class JobProgressUI(parent: SparkUI) {
5151

5252
def formatDuration(ms: Long) = Utils.msDurationToString(ms)
5353

54+
private def handleKillRequest(request: HttpServletRequest) = {
55+
if (killEnabled) {
56+
val killFlag = Option(request.getParameter("terminate")).getOrElse("false").toBoolean
57+
val stageId = Option(request.getParameter("id")).getOrElse("-1").toInt
58+
if (stageId >= 0 && killFlag && listener.activeStages.contains(stageId)) {
59+
sc.cancelStage(stageId)
60+
}
61+
// Do a quick pause here to give Spark time to kill the stage so it shows up as
62+
// killed after the refresh. Note that this will block the serving thread so the
63+
// time should be limited in duration.
64+
Thread.sleep(100)
65+
}
66+
}
67+
5468
def getHandlers = Seq[ServletContextHandler](
69+
createRedirectHandler("/stages/stage/kill", "/stages", handleKillRequest),
5570
createServletHandler("/stages/stage",
5671
(request: HttpServletRequest) => stagePage.render(request), parent.securityManager, basePath),
5772
createServletHandler("/stages/pool",

core/src/main/scala/org/apache/spark/ui/jobs/StageTable.scala

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,20 +76,22 @@ private[ui] class StageTable(
7676
}
7777

7878
private def makeDescription(s: StageInfo): Seq[Node] = {
79+
// scalastyle:off
80+
val killLink = if (killEnabled) {
81+
<span class="kill-link">
82+
(<a href={"%s/stages/stage/kill?id=%s&terminate=true".format(UIUtils.prependBaseUri(basePath), s.stageId)}>kill</a>)
83+
</span>
84+
}
85+
// scalastyle:on
86+
7987
val nameLink =
8088
<a href={"%s/stages/stage?id=%s".format(UIUtils.prependBaseUri(basePath), s.stageId)}>
8189
{s.name}
8290
</a>
83-
val killLink = if (killEnabled) {
84-
<div>[<a href=
85-
{"%s/stages?id=%s&terminate=true".format(UIUtils.prependBaseUri(basePath), s.stageId)}>
86-
Kill
87-
</a>]</div>
8891

89-
}
9092
val description = listener.stageIdToDescription.get(s.stageId)
9193
.map(d => <div><em>{d}</em></div><div>{nameLink} {killLink}</div>)
92-
.getOrElse(<div>{nameLink} {killLink}</div>)
94+
.getOrElse(<div> {killLink}{nameLink}</div>)
9395

9496
return description
9597
}

0 commit comments

Comments
 (0)