From 0c81cbce4b65d8d532105adc307d222feff436dc Mon Sep 17 00:00:00 2001 From: "Patrik J. Braun" Date: Sat, 28 Dec 2019 11:58:40 +0100 Subject: [PATCH] improving jobs --- gulpfile.ts | 2 +- src/backend/model/jobs/JobManager.ts | 14 ++++---- src/backend/model/jobs/jobs/FileJob.ts | 10 ++++-- src/backend/model/jobs/jobs/IJob.ts | 4 +-- src/backend/model/jobs/jobs/Job.ts | 33 +++++++++++-------- .../model/jobs/jobs/ThumbnailGenerationJob.ts | 3 +- src/backend/server.ts | 1 + src/common/config/public/ConfigClass.ts | 4 ++- src/frontend/app/pipes/DurationPipe.ts | 8 ++++- .../app/ui/admin/admin.component.html | 14 ++++++-- src/frontend/app/ui/admin/admin.component.ts | 8 ++--- .../settings/jobs/jobs.settings.component.css | 2 +- .../jobs/jobs.settings.component.html | 25 +++++++++++--- .../settings/jobs/jobs.settings.component.ts | 10 +++++- .../job-progress.settings.component.html | 9 ++--- 15 files changed, 100 insertions(+), 47 deletions(-) diff --git a/gulpfile.ts b/gulpfile.ts index dfcfde6a..b9499334 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -144,7 +144,7 @@ gulp.task('copy-package', function () { json.buildTime = (new Date()).toISOString(); try { - json.buildCommitHash = require('child_process').execSync('git rev-parse HEAD'); + json.buildCommitHash = require('child_process').execSync('git rev-parse HEAD').toString().trim(); } catch (e) { } diff --git a/src/backend/model/jobs/JobManager.ts b/src/backend/model/jobs/JobManager.ts index 9a81a9ed..cf954732 100644 --- a/src/backend/model/jobs/JobManager.ts +++ b/src/backend/model/jobs/JobManager.ts @@ -6,7 +6,7 @@ import {Config} from '../../../common/config/private/Config'; import {AfterJobTrigger, JobScheduleDTO, JobTriggerType} from '../../../common/entities/job/JobScheduleDTO'; import {Logger} from '../../Logger'; import {NotificationManager} from '../NotifocationManager'; -import {JobLastRunDTO} from '../../../common/entities/job/JobLastRunDTO'; +import {JobLastRunDTO, JobLastRunState} from '../../../common/entities/job/JobLastRunDTO'; declare var global: NodeJS.Global; @@ -42,8 +42,8 @@ export class JobManager implements IJobManager { async run(jobName: string, config: T): Promise { const t = this.findJob(jobName); if (t) { - await t.start(config, () => { - this.onJobFinished(t); + await t.start(config, (status: JobLastRunState) => { + this.onJobFinished(t, status); }); } else { Logger.warn(LOG_TAG, 'cannot find job to start:' + jobName); @@ -54,15 +54,15 @@ export class JobManager implements IJobManager { const t = this.findJob(jobName); if (t) { t.stop(); - if (global.gc) { - global.gc(); - } } else { Logger.warn(LOG_TAG, 'cannot find job to stop:' + jobName); } } - async onJobFinished(job: IJob): Promise { + async onJobFinished(job: IJob, status: JobLastRunState): Promise { + if (status === JobLastRunState.canceled) { // if it was cancelled do not start the next one + return; + } const sch = Config.Server.Jobs.scheduled.find(s => s.jobName === job.Name); if (sch) { const children = Config.Server.Jobs.scheduled.filter(s => s.trigger.type === JobTriggerType.after && diff --git a/src/backend/model/jobs/jobs/FileJob.ts b/src/backend/model/jobs/jobs/FileJob.ts index 8f18786b..3bf127b0 100644 --- a/src/backend/model/jobs/jobs/FileJob.ts +++ b/src/backend/model/jobs/jobs/FileJob.ts @@ -74,12 +74,13 @@ export abstract class FileJob extends JobDTO { Name: string; @@ -8,7 +8,7 @@ export interface IJob extends JobDTO { Progress: JobProgressDTO; LastRuns: { [key: string]: JobLastRunDTO }; - start(config: T, OnFinishCB: () => void): Promise; + start(config: T, OnFinishCB: (status: JobLastRunState) => void): Promise; stop(): void; diff --git a/src/backend/model/jobs/jobs/Job.ts b/src/backend/model/jobs/jobs/Job.ts index 9154c694..d0933b31 100644 --- a/src/backend/model/jobs/jobs/Job.ts +++ b/src/backend/model/jobs/jobs/Job.ts @@ -32,7 +32,7 @@ export abstract class Job implements IJob { return this.progress; } - public start(config: T, onFinishCB: () => void): Promise { + public start(config: T, onFinishCB: (status: JobLastRunState) => void): Promise { this.OnFinishCB = onFinishCB; if (this.state === JobState.idle && this.Supported) { Logger.info(LOG_TAG, 'Running job: ' + this.Name); @@ -47,6 +47,17 @@ export abstract class Job implements IJob { current: Date.now() } }; + this.lastRuns[JSON.stringify(this.config)] = { + all: 0, + done: 0, + comment: '', + config: this.config, + state: JobLastRunState.finished, + time: { + start: Date.now(), + end: Date.now() + } + }; const pr = new Promise((resolve) => { this.prResolve = resolve; }); @@ -67,6 +78,7 @@ export abstract class Job implements IJob { Logger.info(LOG_TAG, 'Stopping job: ' + this.Name); this.state = JobState.stopping; this.progress.state = JobState.stopping; + this.lastRuns[JSON.stringify(this.config)].state = JobLastRunState.canceled; } public toJSON(): JobDTO { @@ -76,7 +88,7 @@ export abstract class Job implements IJob { }; } - protected OnFinishCB = () => { + protected OnFinishCB = (status: JobLastRunState) => { }; protected abstract async step(): Promise; @@ -84,17 +96,10 @@ export abstract class Job implements IJob { protected abstract async init(): Promise; private onFinish(): void { - this.lastRuns[JSON.stringify(this.config)] = { - all: this.progress.left + this.progress.progress, - done: this.progress.progress, - comment: '', - config: this.config, - state: this.progress.state === JobState.stopping ? JobLastRunState.canceled : JobLastRunState.finished, - time: { - start: this.progress.time.start, - end: Date.now() - } - }; + this.lastRuns[JSON.stringify(this.config)].all = this.progress.left + this.progress.progress; + this.lastRuns[JSON.stringify(this.config)].done = this.progress.progress; + this.lastRuns[JSON.stringify(this.config)].time.end = Date.now(); + this.progress = null; if (global.gc) { global.gc(); @@ -103,7 +108,7 @@ export abstract class Job implements IJob { if (this.IsInstant) { this.prResolve(); } - this.OnFinishCB(); + this.OnFinishCB(this.lastRuns[JSON.stringify(this.config)].state); } private run() { diff --git a/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts b/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts index 80d75a06..46c707d0 100644 --- a/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts +++ b/src/backend/model/jobs/jobs/ThumbnailGenerationJob.ts @@ -7,6 +7,7 @@ import {PhotoProcessing} from '../../fileprocessing/PhotoProcessing'; import {ThumbnailSourceType} from '../../threading/PhotoWorker'; import {MediaDTO} from '../../../../common/entities/MediaDTO'; import {FileDTO} from '../../../../common/entities/FileDTO'; +import {JobLastRunState} from '../../../../common/entities/job/JobLastRunDTO'; const LOG_TAG = '[ThumbnailGenerationJob]'; @@ -28,7 +29,7 @@ export class ThumbnailGenerationJob extends FileJob<{ sizes: number[], indexedOn return true; } - start(config: { sizes: number[], indexedOnly: boolean }, OnFinishCB: () => void): Promise { + start(config: { sizes: number[], indexedOnly: boolean }, OnFinishCB: (status: JobLastRunState) => void): Promise { for (let i = 0; i < config.sizes.length; ++i) { if (Config.Client.Media.Thumbnail.thumbnailSizes.indexOf(config.sizes[i]) === -1) { throw new Error('unknown thumbnails size: ' + config.sizes[i] + '. Add it to the possible thumbnail sizes.'); diff --git a/src/backend/server.ts b/src/backend/server.ts index 6b5a8bc7..7ce219a9 100644 --- a/src/backend/server.ts +++ b/src/backend/server.ts @@ -43,6 +43,7 @@ export class Server { Config.Client.appVersion = require('../../package.json').version; Config.Client.buildTime = require('../../package.json').buildTime; Config.Client.buildCommitHash = require('../../package.json').buildCommitHash; + Config.Client.upTime = (new Date()).toISOString(); Logger.verbose(LOG_TAG, JSON.stringify(Config, null, '\t')); this.app = _express(); diff --git a/src/common/config/public/ConfigClass.ts b/src/common/config/public/ConfigClass.ts index b0f66bf9..5c55ee6b 100644 --- a/src/common/config/public/ConfigClass.ts +++ b/src/common/config/public/ConfigClass.ts @@ -91,6 +91,7 @@ export module ClientConfig { } export interface Config { + upTime: string; appVersion: string; buildTime: string; buildCommitHash: string; @@ -115,13 +116,14 @@ export module ClientConfig { /** * These configuration will be available at frontend and backend too */ -export class PublicConfigClass { +export class PublicConfigClass { public Client: ClientConfig.Config = { applicationTitle: 'PiGallery 2', appVersion: '', buildCommitHash: '', buildTime: '', + upTime: '', Media: { Video: { enabled: true diff --git a/src/frontend/app/pipes/DurationPipe.ts b/src/frontend/app/pipes/DurationPipe.ts index 2ac8843b..cf031e36 100644 --- a/src/frontend/app/pipes/DurationPipe.ts +++ b/src/frontend/app/pipes/DurationPipe.ts @@ -7,13 +7,18 @@ export class DurationPipe implements PipeTransform { constructor(private i18n: I18n) { } - transform(time: number): string { + transform(time: number, separator: ':' | 'string' = 'string'): string { const h = Math.floor(time / 1000 / 60 / 60); time %= 1000 * 60 * 60; const m = Math.floor(time / 1000 / 60); time %= 1000 * 60; const s = Math.floor(time / 1000); + + if (separator === ':') { + const leftPad = (x: any): string => String(x).length >= 2 ? x : leftPad(`0${x}`); + return [h || 0, m || 0, s || 0].map(leftPad).join(':'); + } let str = ''; if (h > 0) { str += h + this.i18n({value: 'h', meaning: 'hour'}); @@ -24,6 +29,7 @@ export class DurationPipe implements PipeTransform { if (s > 0) { str += s + this.i18n({value: 's', meaning: 'second'}); } + return str; } } diff --git a/src/frontend/app/ui/admin/admin.component.html b/src/frontend/app/ui/admin/admin.component.html index 726bb462..3d67efd4 100644 --- a/src/frontend/app/ui/admin/admin.component.html +++ b/src/frontend/app/ui/admin/admin.component.html @@ -106,9 +106,19 @@ [hidden]="!indexing.HasAvailableSettings" [simplifiedMode]="simplifiedMode"> + [hidden]="!jobs.HasAvailableSettings" + [simplifiedMode]="simplifiedMode"> + +
+
+
+ Up time: {{upTime | date:'medium'}} +
+
+
+ diff --git a/src/frontend/app/ui/admin/admin.component.ts b/src/frontend/app/ui/admin/admin.component.ts index caf22c63..272ad3d0 100644 --- a/src/frontend/app/ui/admin/admin.component.ts +++ b/src/frontend/app/ui/admin/admin.component.ts @@ -23,8 +23,7 @@ export class AdminComponent implements OnInit, AfterViewInit { }; appVersion = Config.Client.appVersion; versionExtra = ''; - buildTime = Config.Client.buildTime; - buildCommitHash = Config.Client.buildCommitHash; + upTime = Config.Client.upTime; @ViewChildren('setting') settingsComponents: QueryList; @ViewChildren('setting', {read: ElementRef}) settingsComponents2: QueryList; contents: ISettingsComponent[] = []; @@ -36,6 +35,7 @@ export class AdminComponent implements OnInit, AfterViewInit { public i18n: I18n) { this.text.Advanced = i18n('Advanced'); this.text.Simplified = i18n('Simplified'); + if (Config.Client.buildTime) { this.versionExtra = i18n('Built at') + ': ' + formatDate(Config.Client.buildTime, 'medium', locale); } @@ -51,12 +51,12 @@ export class AdminComponent implements OnInit, AfterViewInit { scrollTo(i: number) { PageHelper.ScrollY = this.settingsComponents2.toArray()[i].nativeElement.getBoundingClientRect().top + - PageHelper.ScrollY; + PageHelper.ScrollY; } ngOnInit() { if (!this._authService.isAuthenticated() - || this._authService.user.value.role < UserRoles.Admin) { + || this._authService.user.value.role < UserRoles.Admin) { this._navigation.toLogin(); return; } diff --git a/src/frontend/app/ui/settings/jobs/jobs.settings.component.css b/src/frontend/app/ui/settings/jobs/jobs.settings.component.css index 681efadb..14cf3e3e 100644 --- a/src/frontend/app/ui/settings/jobs/jobs.settings.component.css +++ b/src/frontend/app/ui/settings/jobs/jobs.settings.component.css @@ -3,7 +3,7 @@ margin-bottom: 1rem; } -.button-delete { +.job-control-button { margin-top: -5px; margin-bottom: -5px; } diff --git a/src/frontend/app/ui/settings/jobs/jobs.settings.component.html b/src/frontend/app/ui/settings/jobs/jobs.settings.component.html index 4ba16978..0b9901b7 100644 --- a/src/frontend/app/ui/settings/jobs/jobs.settings.component.html +++ b/src/frontend/app/ui/settings/jobs/jobs.settings.component.html @@ -9,7 +9,8 @@
-
+
{{schedule.name}} @ @@ -26,11 +27,24 @@ {{schedule.trigger.afterScheduleName}} - +
+ + + +
+
@@ -192,8 +206,9 @@ + *ngIf="getProgress(schedule) || getLastRun(schedule)" + [progress]="getProgress(schedule)" + [lastRun]="getLastRun(schedule)">
diff --git a/src/frontend/app/ui/settings/jobs/jobs.settings.component.ts b/src/frontend/app/ui/settings/jobs/jobs.settings.component.ts index 31604bf8..77ed0135 100644 --- a/src/frontend/app/ui/settings/jobs/jobs.settings.component.ts +++ b/src/frontend/app/ui/settings/jobs/jobs.settings.component.ts @@ -186,7 +186,6 @@ export class JobsSettingsComponent extends SettingsComponent parseInt(s, 10)) .filter((i: number) => !isNaN(i) && i > 0); - console.log(configElement[id]); } getNumberArray(configElement: any, id: string) { @@ -209,12 +208,21 @@ export class JobsSettingsComponent extends SettingsComponent s.jobName === jobName).length; this.newSchedule.name = count === 0 ? jobName : jobName + ' ' + (count + 1); this.settings.scheduled.push(this.newSchedule); + this.jobModal.hide(); } getConfigHash(schedule: JobScheduleDTO): string { return JSON.stringify(schedule.config); } + getProgress(schedule: JobScheduleDTO) { + return this.jobsService.progress.value[schedule.jobName]; + } + + getLastRun(schedule: JobScheduleDTO) { + return (this.jobsService.lastRuns.value[schedule.jobName] || {})[this.getConfigHash(schedule)]; + } + private getNextRunningDate(sch: JobScheduleDTO, list: JobScheduleDTO[], depth: number = 0): number { if (depth > list.length) { return 0; diff --git a/src/frontend/app/ui/settings/jobs/progress/job-progress.settings.component.html b/src/frontend/app/ui/settings/jobs/progress/job-progress.settings.component.html index 7275c564..3a44a232 100644 --- a/src/frontend/app/ui/settings/jobs/progress/job-progress.settings.component.html +++ b/src/frontend/app/ui/settings/jobs/progress/job-progress.settings.component.html @@ -8,7 +8,7 @@
- {{lastRun.all}}/{{lastRun.done}} + {{lastRun.done}}/{{lastRun.all}}
@@ -28,8 +28,9 @@
-
{{TimeElapsed| duration}}
-
+
{{TimeElapsed| duration:':'}}
+
{{TimeAll| duration:':'}}
+
{{progress.progress}}/{{progress.progress + progress.left}}
@@ -48,6 +50,5 @@ aria-valuemin="0" aria-valuemax="100" style="width: 100%">
-
{{TimeAll| duration}}