Skip to content

Commit

Permalink
feat(): change build time algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
Izak88 committed Sep 27, 2017
1 parent 75afa05 commit 4ff60d3
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 79 deletions.
2 changes: 1 addition & 1 deletion src/api/db/build.ts
Expand Up @@ -146,7 +146,7 @@ export function getBuild(id: number, userId?: number): Promise<any> {
.whereNotNull('build_runs.end_time')
.orderBy('build_runs.id', 'desc');
})
.fetch()
.fetch({ withRelated: 'job_runs'})
.then(lastBuild => {
if (lastBuild) {
build.lastBuild = lastBuild.toJSON();
Expand Down
44 changes: 10 additions & 34 deletions src/api/process-manager.ts
Expand Up @@ -151,14 +151,6 @@ function execJob(proc: JobProcess): Observable<{}> {

return dbJobRuns.updateJobRun(data);
})
.then(() => {
jobEvents.next({
type: 'process',
job_id: proc.job_id,
data: 'job failed',
additionalData: time.getTime()
});
})
.then(build => updateBuild({ id: proc.build_id, end_time: time }))
.then(id => updateBuildRun({ id: id, end_time: time }))
.then(() => getBuild(proc.build_id))
Expand All @@ -176,7 +168,8 @@ function execJob(proc: JobProcess): Observable<{}> {
type: 'process',
build_id: proc.build_id,
job_id: proc.job_id,
data: 'job failed'
data: 'job failed',
additionalData: time.getTime()
});
})
.then(() => observer.complete())
Expand Down Expand Up @@ -255,9 +248,12 @@ function execJob(proc: JobProcess): Observable<{}> {
type: 'process',
build_id: proc.build_id,
job_id: proc.job_id,
data: 'job failed'
data: 'job failed',
additionalData: time.getTime()
});

getLastRunId(proc.build_id).then(id => updateBuildRun({ id: id, end_time: time} ));

observer.complete();
});
});
Expand Down Expand Up @@ -289,7 +285,6 @@ function execJob(proc: JobProcess): Observable<{}> {
export function restartJob(jobId: number): Promise<void> {
const time = new Date();
let job = null;
let buildData;

return stopJob(jobId)
.then(() => dbJob.getLastRun(jobId))
Expand All @@ -309,31 +304,12 @@ export function restartJob(jobId: number): Promise<void> {
type: 'process',
build_id: job.builds_id,
job_id: job.id,
data: 'job restarted'
});
})
.then(() => getBuild(job.builds_id))
.then(build => buildData = build)
.then(() => {
let jobs = buildData.jobs;
buildData.start_time = time;
buildData.end_time = null;

return updateBuild(buildData)
.then(() => {
buildData.build_id = job.builds_id;
return insertBuildRun(buildData);
});
})
.then(() => {
jobEvents.next({
type: 'process',
build_id: job.builds_id,
data: 'build restarted',
data: 'job restarted',
additionalData: time.getTime()
});
})
.then(() => sendPendingStatus(buildData, buildData.id))
.then(() => getBuild(job.builds_id))
.then(build => sendPendingStatus(build, build.id))
.catch(err => {
const msg: LogMessageType = { message: `[error]: ${err}`, type: 'error', notify: false };
logger.next(msg);
Expand Down Expand Up @@ -421,7 +397,7 @@ export function stopJob(jobId: number): Promise<void> {
.then(() => dbJob.getLastRunId(jobId))
.then(runId => dbJobRuns.getRun(runId))
.then(jobRun => {
if (jobRun.status !== 'success') {
if (!jobRun.end_time) {
return dbJobRuns.updateJobRun({id: jobRun.id, end_time: time, status: 'failed' });
}
})
Expand Down
Expand Up @@ -90,14 +90,16 @@ <h1 class="bold">
<div class="column is-2">
<p class="text-small">
<span *ngIf="status !== 'running'">Build started {{ timeWords }} ago</span>
<span *ngIf="status === 'running' && previousRuntime && previousRuntime >= (currentTime - totalTime)">approximately {{ previousRuntime - (currentTime - totalTime) | date:'mm:ss' }} remaining</span>
<span *ngIf="status === 'running' && previousRuntime && previousRuntime > 0 && previousRuntime >= (currentTime - minRunningJobStartTime)">approximately {{ previousRuntime - (currentTime - minRunningJobStartTime) | date:'mm:ss' }} remaining</span>
</p>
</div>
<div class="column is-1">
<p class="total-time" *ngIf="!processingBuild">
<img src="images/icons/clock.svg">
<span *ngIf="status !== 'running'">{{ totalTime | toTime }}</span>
<span *ngIf="status === 'running'">{{ currentTime - totalTime | toTime }}</span>
<span *ngIf="status !== 'running' && maxCompletedJobTime">{{ maxCompletedJobTime | toTime }}</span>
<span *ngIf="status !== 'running' && !maxCompletedJobTime">00:00</span>
<span *ngIf="status === 'running' && maxCompletedJobTime > (currentTime - minRunningJobStartTime)">{{ maxCompletedJobTime | toTime }}</span>
<span *ngIf="status === 'running' && (!maxCompletedJobTime || maxCompletedJobTime <= (currentTime - minRunningJobStartTime))">{{ currentTime - minRunningJobStartTime | toTime }}</span>
</p>
</div>
</div>
Expand Down Expand Up @@ -173,8 +175,8 @@ <h1 class="bold">
<div class="column is-1" *ngIf="processingBuild"></div>
<div class="column is-1" *ngIf="!processingBuild">
<span class="job-time" *ngIf="job?.status === 'running'">{{ currentTime - job.start_time | toTime }}</span>
<span class="job-time" *ngIf="job?.status === 'success' || job?.status === 'failed'">{{ job.end_time - job.start_time | toTime }}</span>
<span class="job-time" *ngIf="job?.status === 'queued'">00:00</span>
<span class="job-time" *ngIf="job?.end_time && (job?.status === 'success' || job?.status === 'failed')">{{ job.end_time - job.start_time | toTime }}</span>
<span class="job-time" *ngIf="job?.status === 'queued' || (!job.end_time && (job?.status === 'success' || job?.status === 'failed'))">00:00</span>
</div>
<div class="column is-1" *ngIf="userId && build?.hasPermission">
<span class="icon circle" name="restart-job" (click)="restartJob($event, job.id)" [class.disabled]="job.processing">
Expand Down
47 changes: 30 additions & 17 deletions src/app/components/app-build-details/app-build-details.component.ts
Expand Up @@ -19,7 +19,8 @@ export class AppBuildDetailsComponent implements OnInit, OnDestroy {
build: any;
status: string;
timeWords: string;
totalTime: number;
maxCompletedJobTime: number;
minRunningJobStartTime: number;
previousRuntime: number;
processingBuild: boolean;
tag: string = null;
Expand Down Expand Up @@ -73,8 +74,10 @@ export class AppBuildDetailsComponent implements OnInit, OnDestroy {

this.build.jobs.forEach(job => job.time = '00:00');
this.timeWords = distanceInWordsToNow(this.build.created_at);
this.previousRuntime = 0;
if (this.build.lastBuild) {
this.previousRuntime = this.build.lastBuild.end_time - this.build.lastBuild.start_time;
let maxJobTime = Math.max(...this.build.lastBuild.job_runs.map(job => job.end_time - job.start_time));
maxJobTime ? this.previousRuntime = maxJobTime : this.previousRuntime = 0;
}

this.status = this.getBuildStatus();
Expand All @@ -89,12 +92,29 @@ export class AppBuildDetailsComponent implements OnInit, OnDestroy {
this.build.jobs[index].status = 'running';
this.build.jobs[index].end_time = null;
this.build.jobs[index].start_time = event.additionalData;
this.build.jobs[index].runs.push({ start_time: event.additionalData, end_time: null });
} else if (event.data === 'job succeded') {
this.build.jobs[index].status = 'success';
this.build.jobs[index].end_time = event.additionalData;
} else if (event.data === 'job failed' || event.data === 'job stopped') {
this.build.jobs[index].runs[this.build.jobs[index].runs.length - 1].end_time = event.additionalData;
} else if (event.data === 'job failed') {
this.build.jobs[index].status = 'failed';
this.build.jobs[index].end_time = event.additionalData;
if (!this.build.jobs[index].end_time) {
this.build.jobs[index].end_time = event.additionalData;
}
if (!this.build.jobs[index].runs[this.build.jobs[index].runs.length - 1].end_time) {
this.build.jobs[index].runs[this.build.jobs[index].runs.length - 1].end_time = event.additionalData;
}
} else if (event.data === 'job stopped') {
if (this.build.jobs[index].status !== 'success') {
this.build.jobs[index].status = 'failed';
}
if (!this.build.jobs[index].end_time) {
this.build.jobs[index].end_time = event.additionalData;
}
if (!this.build.jobs[index].runs[this.build.jobs[index].runs.length - 1].end_time) {
this.build.jobs[index].runs[this.build.jobs[index].runs.length - 1].end_time = event.additionalData;
}
} else if (event.data === 'job queued') {
this.build.jobs[index].status = 'queued';
}
Expand All @@ -118,11 +138,9 @@ export class AppBuildDetailsComponent implements OnInit, OnDestroy {
if (event.build_id === Number(this.id)) {
if (event.data === 'build restarted') {
this.build.start_time = event.additionalData;
this.updateJobTimes();
this.processingBuild = false;
} else {
this.build.end_time = event.additionalData;
this.updateJobTimes();
}
}
});
Expand Down Expand Up @@ -152,14 +170,9 @@ export class AppBuildDetailsComponent implements OnInit, OnDestroy {
}

updateJobTimes(): void {
if (this.status !== 'running') {
if (this.build.end_time > this.build.start_time) {
this.totalTime = this.build.end_time - this.build.start_time;
} else {
this.totalTime = 0;
}
} else {
this.totalTime = Math.min(...this.build.jobs
this.maxCompletedJobTime = Math.max(...this.build.jobs.map(job => job.end_time - job.start_time));
if (this.status === 'running') {
this.minRunningJobStartTime = Math.min(...this.build.jobs
.filter(job => job.status === 'running').map(job => job.start_time));
}

Expand Down Expand Up @@ -224,9 +237,9 @@ export class AppBuildDetailsComponent implements OnInit, OnDestroy {
e.preventDefault();
e.stopPropagation();

let minJobStartTime = Math.min(...this.build.jobs.map(job => job.start_time));
let maxJobEndTime = Math.max(...this.build.jobs.map(job => job.end_time));
this.previousRuntime = maxJobEndTime - minJobStartTime;
this.previousRuntime = 0;
let maxJobTime = Math.max(...this.build.jobs.map(job => job.end_time - job.start_time));
maxJobTime ? this.previousRuntime = maxJobTime : this.previousRuntime = 0;
this.processingBuild = true;
this.socketService.emit({ type: 'restartBuild', data: { buildId: id } });
}
Expand Down
Expand Up @@ -39,8 +39,9 @@
<span *ngIf="tag">{{ build?.data?.head_commit?.comitter?.name }}</span>
</div>
<div class="column is-1">
<span class="build-time" *ngIf="build?.status === 'running'">{{ currentTime - build?.startTime | toTime }} </span>
<span class="build-time" *ngIf="build?.status !== 'running'">{{ build?.maxTime | toTime }}</span>
<span class="build-time" *ngIf="build?.status === 'running' && build?.maxCompletedJobTime && build?.minRunningJobStartTime && build?.maxCompletedJobTime > (currentTime - build?.minRunningJobStartTime)">{{ build?.maxCompletedJobTime | toTime }} </span>
<span class="build-time" *ngIf="build?.status === 'running' && build?.maxCompletedJobTime && build?.minRunningJobStartTime && build?.maxCompletedJobTime <= (currentTime - build?.minRunningJobStartTime)">{{ currentTime - build?.minRunningJobStartTime | toTime }} </span>
<span class="build-time" *ngIf="build?.status !== 'running' && build?.maxCompletedJobTime">{{ build?.maxCompletedJobTime | toTime }}</span>
</div>
<div class="column is-1 justify-end" *ngIf="build?.userId && build?.hasPermission">
<span class="icon circle restart-build" (click)="restartBuild($event, build.id)" [class.disabled]="processingRequest">
Expand Down
12 changes: 2 additions & 10 deletions src/app/components/app-builds/app-builds.component.ts
Expand Up @@ -107,7 +107,6 @@ export class AppBuildsComponent implements OnInit, OnDestroy {
if (index !== -1) {
if (event.data === 'build restarted') {
this.builds[index].start_time = event.additionalData;
this.update();
} else {
this.builds[index].end_time = event.additionalData;
this.update();
Expand Down Expand Up @@ -145,15 +144,8 @@ export class AppBuildsComponent implements OnInit, OnDestroy {
status = 'success';
}

if (status !== 'running') {
if (build.end_time > build.start_time) {
build.maxTime = build.end_time - build.start_time;
} else {
build.maxTime = 0;
}
}

build.startTime = Math.min(...build.jobs
build.maxCompletedJobTime = Math.max(...build.jobs.map(job => job.end_time - job.start_time));
build.minRunningJobStartTime = Math.min(...build.jobs
.filter(job => job.status === 'running')
.map(job => job.start_time));
build.status = status;
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/app-job/app-job.component.html
Expand Up @@ -96,7 +96,7 @@ <h2 *ngIf="commitMessage">{{ commitMessage }}</h2>
<p class="total-time">
<img src="images/icons/clock.svg">
<span *ngIf="jobRun.status === 'running'">{{ currentTime - jobRun.start_time | toTime }}</span>
<span *ngIf="jobRun.status !== 'running'">{{ jobRun.end_time - jobRun.start_time | toTime }}</span>
<span *ngIf="jobRun.status !== 'running' && jobRun.end_time">{{ jobRun.end_time - jobRun.start_time | toTime }}</span>
</p>
</div>

Expand Down
11 changes: 2 additions & 9 deletions src/app/components/app-repository/app-repository.component.ts
Expand Up @@ -275,15 +275,8 @@ export class AppRepositoryComponent implements OnInit, OnDestroy {
status = 'success';
}

if (status !== 'running') {
if (build.end_time > build.start_time) {
build.maxTime = build.end_time - build.start_time;
} else {
build.maxTime = new Date().getTime() - build.start_time;
}
}

build.startTime = Math.min(...build.jobs
build.maxCompletedJobTime = Math.max(...build.jobs.map(job => job.end_time - job.start_time));
build.minRunningJobStartTime = Math.min(...build.jobs
.filter(job => job.status === 'running')
.map(job => job.start_time));
build.status = status;
Expand Down

0 comments on commit 4ff60d3

Please sign in to comment.