Separate queue wait from build duration
BuildResult gains runningSince, set when a build leaves the queue; the recorded duration now measures pure build time from that point, so build runtimes can be tracked without queue wait. A build cancelled while still queued records neither. The UI shows the live wait time in italics while pending and switches to the real build time once the build runs; the Gitea "after mm:ss" descriptions now also report pure build time. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a03f85bc17
commit
56aa306481
@@ -120,6 +120,7 @@ class BuildExecutor(
|
||||
return
|
||||
}
|
||||
build.running = true
|
||||
build.runningBuild.runningSince = Instant.now()
|
||||
transition(build, BuildStatus.RUNNING, duration = null)
|
||||
val preparedWorkspace =
|
||||
workspaces.prepare(
|
||||
@@ -140,7 +141,8 @@ class BuildExecutor(
|
||||
log.error("build of branch {} crashed", build.runningBuild.branch, e)
|
||||
appendToLiveLog(build, "\nbuild crashed: ${e.message}\n")
|
||||
} finally {
|
||||
val duration = Duration.between(build.runningBuild.startedAt, Instant.now())
|
||||
// pure build time, without the queue wait; null when the build never started executing
|
||||
val duration = build.runningBuild.runningSince?.let { Duration.between(it, Instant.now()) }
|
||||
val result = transition(build, finalStatus, duration)
|
||||
try {
|
||||
artifactStore.persist(result, build.runningBuild.stagingDir, workspace)
|
||||
@@ -277,12 +279,17 @@ class BuildExecutor(
|
||||
val runningBuild = build.runningBuild
|
||||
val updated =
|
||||
repository.updateByArtifactKey(runningBuild.artifactKey) {
|
||||
it.copy(status = status, duration = duration ?: it.duration)
|
||||
it.copy(
|
||||
status = status,
|
||||
runningSince = runningBuild.runningSince ?: it.runningSince,
|
||||
duration = duration ?: it.duration,
|
||||
)
|
||||
} ?: BuildResult(
|
||||
branch = runningBuild.branch,
|
||||
commit = runningBuild.commit,
|
||||
status = status,
|
||||
startedAt = runningBuild.startedAt,
|
||||
runningSince = runningBuild.runningSince,
|
||||
duration = duration,
|
||||
artifactKey = runningBuild.artifactKey,
|
||||
).also { repository.append(it) }
|
||||
|
||||
@@ -7,7 +7,11 @@ data class BuildResult(
|
||||
val branch: String,
|
||||
val commit: String,
|
||||
val status: BuildStatus,
|
||||
/** When the build was accepted (enqueued); the time until [runningSince] is queue wait. */
|
||||
val startedAt: Instant,
|
||||
/** When the build actually started executing; null while queued or when cancelled in the queue. */
|
||||
val runningSince: Instant? = null,
|
||||
/** Pure build execution time (from [runningSince]), without the queue wait. */
|
||||
val duration: Duration? = null,
|
||||
val artifactKey: String,
|
||||
)
|
||||
|
||||
@@ -13,7 +13,11 @@ data class RunningBuild(
|
||||
val stagingDir: Path,
|
||||
/** Combined stdout+stderr log, written live while the build runs. */
|
||||
val liveLogFile: Path,
|
||||
)
|
||||
) {
|
||||
/** Set by the executor when the build leaves the queue and starts executing. */
|
||||
@Volatile
|
||||
var runningSince: Instant? = null
|
||||
}
|
||||
|
||||
/** Published via Spring's `ApplicationEventPublisher` on every persisted status transition. */
|
||||
data class BuildStatusChangedEvent(
|
||||
|
||||
@@ -13,6 +13,8 @@ data class BuildResultDto(
|
||||
val commit: String,
|
||||
val status: String,
|
||||
val startedAt: Instant,
|
||||
/** When the build left the queue; the UI derives the live build time from this, the wait time from [startedAt]. */
|
||||
val runningSince: Instant? = null,
|
||||
val durationSeconds: Long?,
|
||||
val artifactKey: String,
|
||||
) {
|
||||
@@ -23,6 +25,7 @@ data class BuildResultDto(
|
||||
commit = result.commit,
|
||||
status = result.status.jsonName,
|
||||
startedAt = result.startedAt,
|
||||
runningSince = result.runningSince,
|
||||
durationSeconds = result.duration?.seconds,
|
||||
artifactKey = result.artifactKey,
|
||||
)
|
||||
@@ -40,6 +43,7 @@ data class BranchDto(
|
||||
val commit: String,
|
||||
val status: String,
|
||||
val startedAt: Instant?,
|
||||
val runningSince: Instant? = null,
|
||||
val durationSeconds: Long?,
|
||||
val artifactKey: String,
|
||||
val latestGreenUrl: String? = null,
|
||||
@@ -65,6 +69,7 @@ data class BranchDto(
|
||||
commit = latest.commit,
|
||||
status = latest.status.jsonName,
|
||||
startedAt = latest.startedAt,
|
||||
runningSince = latest.runningSince,
|
||||
durationSeconds = latest.duration?.seconds,
|
||||
artifactKey = latest.artifactKey,
|
||||
latestGreenUrl = if (hasGreenBuild) BranchPermalinks.permanentUrl(branch) else null,
|
||||
@@ -80,6 +85,7 @@ data class CurrentBuildDto(
|
||||
val artifactKey: String,
|
||||
val status: String,
|
||||
val startedAt: Instant,
|
||||
val runningSince: Instant? = null,
|
||||
val logSize: Long,
|
||||
)
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ class BuildsApiController(
|
||||
(results.firstOrNull { it.artifactKey == build.artifactKey }?.status ?: BuildStatus.RUNNING)
|
||||
.jsonName,
|
||||
startedAt = build.startedAt,
|
||||
runningSince = build.runningSince,
|
||||
logSize = liveLogSize(build.liveLogFile),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ class UiController(
|
||||
.jsonName,
|
||||
startedAtIso = build.startedAt.toString(),
|
||||
startedAt = UiFormats.timestamp(build.startedAt),
|
||||
runningSinceIso = build.runningSince?.toString() ?: "",
|
||||
artifactKey = build.artifactKey,
|
||||
branchUrl = links.branchUrl(build.branch),
|
||||
commitUrl = links.commitUrl(build.commit),
|
||||
|
||||
@@ -75,6 +75,8 @@ data class BuildRowView(
|
||||
val status: String,
|
||||
val startedAtIso: String,
|
||||
val startedAt: String,
|
||||
/** ISO timestamp of the run start for the live build-time ticker; empty while queued. */
|
||||
val runningSinceIso: String,
|
||||
val duration: String,
|
||||
val artifactKey: String,
|
||||
val branchUrl: String?,
|
||||
@@ -94,6 +96,7 @@ data class BuildRowView(
|
||||
status = result.status.jsonName,
|
||||
startedAtIso = result.startedAt.toString(),
|
||||
startedAt = UiFormats.timestamp(result.startedAt),
|
||||
runningSinceIso = result.runningSince?.toString() ?: "",
|
||||
duration = UiFormats.duration(result.duration),
|
||||
artifactKey = result.artifactKey,
|
||||
branchUrl = links.branchUrl(result.branch),
|
||||
@@ -112,6 +115,7 @@ data class BuildRowView(
|
||||
status = entry.status,
|
||||
startedAtIso = entry.startedAt?.toString() ?: "",
|
||||
startedAt = entry.startedAt?.let { UiFormats.timestamp(it) } ?: "",
|
||||
runningSinceIso = entry.runningSince?.toString() ?: "",
|
||||
duration = UiFormats.duration(entry.durationSeconds?.let { Duration.ofSeconds(it) }),
|
||||
artifactKey = entry.artifactKey,
|
||||
branchUrl = links.branchUrl(entry.branch),
|
||||
@@ -130,6 +134,7 @@ data class CurrentBuildView(
|
||||
val status: String,
|
||||
val startedAtIso: String,
|
||||
val startedAt: String,
|
||||
val runningSinceIso: String,
|
||||
val artifactKey: String,
|
||||
val branchUrl: String?,
|
||||
val commitUrl: String?,
|
||||
|
||||
Reference in New Issue
Block a user