Skip to content

Commit

Permalink
Fixes statuses on the stuck page (#271)
Browse files Browse the repository at this point in the history
- status was "running" for every stuck execution
- added sorting as well
  • Loading branch information
dufrannea authored and Adrien Surée committed Apr 25, 2018
1 parent f9b8269 commit f8f815c
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 60 deletions.
127 changes: 70 additions & 57 deletions core/src/main/javascript/app/pages/ExecutionLogs.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,15 @@ type Props = {
sort: { column: string, order: "asc" | "desc" }
) => string,
columns: Array<

| "job"
| "context"
| "startTime"
| "failed"
| "retry"
| "endTime"
| "status"
| "detail"
| "lastFailure"
| "job"
| "context"
| "startTime"
| "failed"
| "retry"
| "endTime"
| "status"
| "detail"
| "lastFailure"
>,
label: string,
page: number,
Expand Down Expand Up @@ -221,7 +220,9 @@ class ExecutionLogs extends React.Component {
const { start, end } = context;
return (
<TimeRangeLink
href={`/timeseries/calendar/${urlFormat(start)}_${urlFormat(end)}`}
href={`/timeseries/calendar/${urlFormat(
start
)}_${urlFormat(end)}`}
start={start}
end={end}
/>
Expand All @@ -245,12 +246,14 @@ class ExecutionLogs extends React.Component {
<Clock className={classes.time} time={endTime || ""} />
);
case "retry":
return status === "running"
? "Now"
: <Clock
className={classes.time}
time={(failing && failing.nextRetry) || ""}
/>;
return status === "running" ? (
"Now"
) : (
<Clock
className={classes.time}
time={(failing && failing.nextRetry) || ""}
/>
);
case "status":
return (
<Link
Expand All @@ -270,7 +273,11 @@ class ExecutionLogs extends React.Component {
</Link>
);
case "lastFailure":
const lastFailedUrl = `/executions/${failing.failedExecutions[failing.failedExecutions.length - 1].id}`;
const lastFailedUrl = `/executions/${
failing.failedExecutions[
failing.failedExecutions.length - 1
].id
}`;

return (
<Link href={lastFailedUrl}>
Expand All @@ -284,11 +291,7 @@ class ExecutionLogs extends React.Component {
} else if (data) {
return (
<div className={classes.noData}>
No
{" "}
{label}
{" "}
executions for now
No {label} executions for now
{selectedJobs.length ? " (some may have been filtered)" : ""}
</div>
);
Expand All @@ -306,7 +309,11 @@ class ExecutionLogs extends React.Component {
let pageCount = Math.ceil(total / rowsPerPage);
return (
<div className={classes.footer}>
{`${numeral(page * rowsPerPage + 1).format("0,0")} to ${numeral(Math.min(total, page * rowsPerPage + rowsPerPage)).format("0,0")} of ${numeral(total).format("0,0")} ${label} executions`}
{`${numeral(page * rowsPerPage + 1).format("0,0")} to ${numeral(
Math.min(total, page * rowsPerPage + rowsPerPage)
).format("0,0")} of ${numeral(total).format(
"0,0"
)} ${label} executions`}
<ReactPaginate
pageCount={pageCount}
pageRangeDisplayed={3}
Expand Down Expand Up @@ -434,9 +441,7 @@ const mapDispatchToProps = dispatch => ({
});

export const Finished = connect(mapStateToProps, mapDispatchToProps)(
injectSheet(
styles
)(
injectSheet(styles)(
({
classes,
workflow,
Expand All @@ -461,9 +466,13 @@ export const Finished = connect(mapStateToProps, mapDispatchToProps)(
workflow={workflow}
columns={["job", "context", "endTime", "status", "detail"]}
request={(page, rowsPerPage, sort) =>
`/api/executions/status/finished?events=true&offset=${page * rowsPerPage}&limit=${rowsPerPage}&sort=${sort.column}&order=${sort.order}${jobsFilter}`}
`/api/executions/status/finished?events=true&offset=${page *
rowsPerPage}&limit=${rowsPerPage}&sort=${sort.column}&order=${
sort.order
}${jobsFilter}`
}
label="finished"
sort={{ column: sort || "endTime", order: order || "desc" }}
sort={{ column: sort || "endTime", order: order || "desc" }}
selectedJobs={selectedJobs}
/>
</div>
Expand All @@ -473,9 +482,7 @@ export const Finished = connect(mapStateToProps, mapDispatchToProps)(
);

export const Started = connect(mapStateToProps, mapDispatchToProps)(
injectSheet(
styles
)(
injectSheet(styles)(
({
classes,
workflow,
Expand All @@ -501,9 +508,9 @@ export const Started = connect(mapStateToProps, mapDispatchToProps)(
});

menuItems.push(
<span
onClick={pauseFiltered}
>{`Pause ${selectedJobs.length} filtered jobs`}</span>
<span onClick={pauseFiltered}>{`Pause ${
selectedJobs.length
} filtered jobs`}</span>
);
} else {
const pauseAll = () =>
Expand All @@ -527,9 +534,13 @@ export const Started = connect(mapStateToProps, mapDispatchToProps)(
workflow={workflow}
columns={["job", "context", "startTime", "status", "detail"]}
request={(page, rowsPerPage, sort) =>
`/api/executions/status/started?events=true&offset=${page * rowsPerPage}&limit=${rowsPerPage}&sort=${sort.column}&order=${sort.order}${jobsFilter}`}
`/api/executions/status/started?events=true&offset=${page *
rowsPerPage}&limit=${rowsPerPage}&sort=${sort.column}&order=${
sort.order
}${jobsFilter}`
}
label="started"
sort={{ column: sort || "context", order: order || "asc"}}
sort={{ column: sort || "context", order: order || "asc" }}
selectedJobs={selectedJobs}
/>
</div>
Expand All @@ -539,9 +550,7 @@ export const Started = connect(mapStateToProps, mapDispatchToProps)(
);

export const Paused = connect(mapStateToProps, mapDispatchToProps)(
injectSheet(
styles
)(
injectSheet(styles)(
({
classes,
workflow,
Expand All @@ -567,9 +576,9 @@ export const Paused = connect(mapStateToProps, mapDispatchToProps)(
});

menuItems.push(
<span
onClick={resumeFiltered}
>{`Resume ${selectedJobs.length} filtered jobs`}</span>
<span onClick={resumeFiltered}>{`Resume ${
selectedJobs.length
} filtered jobs`}</span>
);
} else {
const resumeAll = () =>
Expand All @@ -593,7 +602,11 @@ export const Paused = connect(mapStateToProps, mapDispatchToProps)(
workflow={workflow}
columns={["job", "context", "status", "detail"]}
request={(page, rowsPerPage, sort) =>
`/api/executions/status/paused?events=true&offset=${page * rowsPerPage}&limit=${rowsPerPage}&sort=${sort.column}&order=${sort.order}${jobsFilter}`}
`/api/executions/status/paused?events=true&offset=${page *
rowsPerPage}&limit=${rowsPerPage}&sort=${sort.column}&order=${
sort.order
}${jobsFilter}`
}
label="paused"
sort={{ column: sort || "context", order: order || "asc" }}
selectedJobs={selectedJobs}
Expand All @@ -605,9 +618,7 @@ export const Paused = connect(mapStateToProps, mapDispatchToProps)(
);

export const Stuck = connect(mapStateToProps, mapDispatchToProps)(
injectSheet(
styles
)(
injectSheet(styles)(
({
classes,
workflow,
Expand Down Expand Up @@ -637,11 +648,7 @@ export const Stuck = connect(mapStateToProps, mapDispatchToProps)(
<h1 className={classes.title}>Stuck executions</h1>
<PopoverMenu
className={classes.menu}
items={[
<span onClick={relaunch}>
Relaunch everything now
</span>
]}
items={[<span onClick={relaunch}>Relaunch everything now</span>]}
/>
<ExecutionLogs
envCritical={envCritical}
Expand All @@ -658,7 +665,11 @@ export const Stuck = connect(mapStateToProps, mapDispatchToProps)(
"detail"
]}
request={(page, rowsPerPage, sort) =>
`/api/executions/status/stuck?events=true&offset=${page * rowsPerPage}&limit=${rowsPerPage}&sort=${sort.column}&order=${sort.order}${jobsFilter}${isFilterApplied ? `&${jobsFilter}` : ""}`}
`/api/executions/status/stuck?events=true&offset=${page *
rowsPerPage}&limit=${rowsPerPage}&sort=${sort.column}&order=${
sort.order
}${isFilterApplied ? `&${jobsFilter}` : ""}`
}
label="stuck"
sort={{ column: sort || "failed", order: order || "asc" }}
selectedJobs={selectedJobs}
Expand All @@ -670,9 +681,7 @@ export const Stuck = connect(mapStateToProps, mapDispatchToProps)(
);

export const BackfillsExecutions = connect(mapStateToProps, mapDispatchToProps)(
injectSheet(
styles
)(
injectSheet(styles)(
({
classes,
workflow,
Expand All @@ -698,7 +707,11 @@ export const BackfillsExecutions = connect(mapStateToProps, mapDispatchToProps)(
workflow={workflow}
columns={["job", "context", "status", "detail"]}
request={(page, rowsPerPage, sort) =>
`/api/timeseries/backfills/${backfillId}/executions?events=true&offset=${page * rowsPerPage}&limit=${rowsPerPage}&sort=${sort.column}&order=${sort.order}${jobsFilter}`}
`/api/timeseries/backfills/${backfillId}/executions?events=true&offset=${page *
rowsPerPage}&limit=${rowsPerPage}&sort=${sort.column}&order=${
sort.order
}${jobsFilter}`
}
label=""
sort={{ column: sort || "failed", order: order || "asc" }}
selectedJobs={selectedJobs}
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/com/criteo/cuttle/App.scala
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,11 @@ private[cuttle] case class App[S <: Scheduling](project: CuttleProject[S], execu
Gauge("cuttle_jvm_uptime_seconds").set(getJVMUptime)
Ok(Prometheus.serialize(metrics))

case GET at url"/api/executions/status/$kind?limit=$l&offset=$o&events=$events&sort=$sort&order=$a&jobs=$jobs" =>
case GET at url"/api/executions/status/$kind?limit=$l&offset=$o&events=$events&sort=$sort&order=$order&jobs=$jobs" =>
val jobIds = parseJobIds(jobs)
val limit = Try(l.toInt).toOption.getOrElse(25)
val offset = Try(o.toInt).toOption.getOrElse(0)
val asc = a.toLowerCase == "asc"
val asc = order.toLowerCase == "asc"
val ids = if (jobIds.isEmpty) allIds else jobIds

def getExecutions: IO[Option[(Int, List[ExecutionLog])]] = kind match {
Expand Down
12 changes: 11 additions & 1 deletion core/src/main/scala/com/criteo/cuttle/Executor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -391,11 +391,19 @@ class Executor[S <: Scheduling] private[cuttle] (val platforms: Seq[ExecutionPla
val runningIds = runningState.collect {
case (e: Execution[S], _) if filteredJobs.contains(e.job.id) => (e.job.id, e.context) -> e
}
val waitingExecutions = platforms.flatMap(_.waiting).toSet

recentFailures
.flatMap({
case ((job, context), (_, failingJob)) =>
runningIds.get((job.id, context)).map((_, failingJob, ExecutionRunning))
runningIds
.get((job.id, context))
.map(execution => {
val status =
if (execution.isWaiting.get || waitingExecutions.contains(execution)) ExecutionWaiting
else ExecutionRunning
(execution, failingJob, status)
})
})
.toSeq
}
Expand Down Expand Up @@ -545,6 +553,8 @@ class Executor[S <: Scheduling] private[cuttle] (val platforms: Seq[ExecutionPla
_.sortBy({ case (execution, failingJob, _) => (failingJob.failedExecutions.size, execution) })
case "retry" =>
_.sortBy({ case (execution, failingJob, _) => (failingJob.nextRetry.map(_.toString), execution) })
case "status" =>
_.sortBy({ case (_, _, status) => status.toString })
case _ =>
_.sortBy({ case (execution, _, _) => execution })
}
Expand Down

0 comments on commit f8f815c

Please sign in to comment.