diff --git a/src/backend/middlewares/admin/SettingsMWs.ts b/src/backend/middlewares/admin/SettingsMWs.ts index efc364a0..fe688644 100644 --- a/src/backend/middlewares/admin/SettingsMWs.ts +++ b/src/backend/middlewares/admin/SettingsMWs.ts @@ -5,6 +5,7 @@ import {Config} from '../../../common/config/private/Config'; import {ConfigDiagnostics} from '../../model/diagnostics/ConfigDiagnostics'; import {ConfigClassBuilder} from '../../../../node_modules/typeconfig/node'; import {TAGS} from '../../../common/config/public/ClientConfig'; +import {ObjectManagers} from '../../model/ObjectManagers'; const LOG_TAG = '[SettingsMWs]'; @@ -47,6 +48,8 @@ export class SettingsMWs { Config[settingsPath] = settings; await original.save(); await ConfigDiagnostics.runDiagnostics(); + // restart all schedule timers. In case they have changed + ObjectManagers.getInstance().JobManager.runSchedules(); Logger.info(LOG_TAG, 'new config:'); Logger.info(LOG_TAG, JSON.stringify(Config.toJSON({attachDescription: false}), null, '\t')); return next(); diff --git a/src/backend/model/jobs/JobManager.ts b/src/backend/model/jobs/JobManager.ts index 6d40ad48..09118191 100644 --- a/src/backend/model/jobs/JobManager.ts +++ b/src/backend/model/jobs/JobManager.ts @@ -1,4 +1,4 @@ -import {JobProgressDTO, JobProgressStates,} from '../../../common/entities/job/JobProgressDTO'; +import {JobProgressStates, OnTimerJobProgressDTO,} from '../../../common/entities/job/JobProgressDTO'; import {IJob} from './jobs/IJob'; import {JobRepository} from './JobRepository'; import {Config} from '../../../common/config/private/Config'; @@ -8,6 +8,8 @@ import {NotificationManager} from '../NotifocationManager'; import {IJobListener} from './jobs/IJobListener'; import {JobProgress} from './jobs/JobProgress'; import {JobProgressManager} from './JobProgressManager'; +import {JobDTOUtils} from '../../../common/entities/job/JobDTO'; +import {Utils} from '../../../common/Utils'; const LOG_TAG = '[JobManager]'; @@ -22,33 +24,35 @@ export class JobManager implements IJobListener { protected get JobRunning(): boolean { return ( - JobRepository.Instance.getAvailableJobs().findIndex( - (j): boolean => j.InProgress === true - ) !== -1 + JobRepository.Instance.getAvailableJobs().findIndex( + (j): boolean => j.InProgress === true + ) !== -1 ); } protected get JobNoParallelRunning(): boolean { return ( - JobRepository.Instance.getAvailableJobs().findIndex( - (j): boolean => j.InProgress === true && j.allowParallelRun - ) !== -1 + JobRepository.Instance.getAvailableJobs().findIndex( + (j): boolean => j.InProgress === true && j.allowParallelRun + ) !== -1 ); } - getProgresses(): { [id: string]: JobProgressDTO } { - return this.progressManager.Progresses; + public getProgresses(): { [id: string]: OnTimerJobProgressDTO } { + const prg = Utils.clone(this.progressManager.Progresses); + this.timers.forEach(t => (prg[JobDTOUtils.getHashName(t.schedule.jobName, t.schedule.config)] as OnTimerJobProgressDTO).onTimer = true); + return prg; } - async run( - jobName: string, - config: T, - soloRun: boolean, - allowParallelRun: boolean + public async run( + jobName: string, + config: T, + soloRun: boolean, + allowParallelRun: boolean ): Promise { if ( - (allowParallelRun === false && this.JobRunning === true) || - this.JobNoParallelRunning === true + (allowParallelRun === false && this.JobRunning === true) || + this.JobNoParallelRunning === true ) { throw new Error('Can\'t start this job while another is running'); } @@ -62,7 +66,7 @@ export class JobManager implements IJobListener { } } - stop(jobName: string): void { + public stop(jobName: string): void { const t = this.findJob(jobName); if (t) { t.cancel(); @@ -71,40 +75,40 @@ export class JobManager implements IJobListener { } } - onProgressUpdate = (progress: JobProgress): void => { + public onProgressUpdate = (progress: JobProgress): void => { this.progressManager.onJobProgressUpdate(progress.toDTO()); }; onJobFinished = async ( - job: IJob, - state: JobProgressStates, - soloRun: boolean + job: IJob, + state: JobProgressStates, + soloRun: boolean ): Promise => { // if it was not finished peacefully or was a soloRun, do not start the next one if (state !== JobProgressStates.finished || soloRun === true) { return; } const sch = Config.Jobs.scheduled.find( - (s): boolean => s.jobName === job.Name + (s): boolean => s.jobName === job.Name ); if (sch) { const children = Config.Jobs.scheduled.filter( - (s): boolean => - s.trigger.type === JobTriggerType.after && - (s.trigger as AfterJobTrigger).afterScheduleName === sch.name + (s): boolean => + s.trigger.type === JobTriggerType.after && + (s.trigger as AfterJobTrigger).afterScheduleName === sch.name ); for (const item of children) { try { await this.run( - item.jobName, - item.config, - false, - item.allowParallelRun + item.jobName, + item.config, + false, + item.allowParallelRun ); } catch (e) { NotificationManager.warning( - 'Job running error:' + item.name, - e.toString() + 'Job running error:' + item.name, + e.toString() ); } } @@ -138,25 +142,25 @@ export class JobManager implements IJobListener { */ private runSchedule(schedule: JobScheduleDTO): void { const nextDate = JobScheduleDTOUtils.getNextRunningDate( - new Date(), - schedule + new Date(), + schedule ); if (nextDate && nextDate.getTime() > Date.now()) { Logger.debug( - LOG_TAG, - 'running schedule: ' + - schedule.jobName + - ' at ' + - nextDate.toLocaleString(undefined, {hour12: false}) + LOG_TAG, + 'running schedule: ' + + schedule.jobName + + ' at ' + + nextDate.toLocaleString(undefined, {hour12: false}) ); const timer: NodeJS.Timeout = setTimeout(async (): Promise => { this.timers = this.timers.filter((t): boolean => t.timer !== timer); await this.run( - schedule.jobName, - schedule.config, - false, - schedule.allowParallelRun + schedule.jobName, + schedule.config, + false, + schedule.allowParallelRun ); this.runSchedule(schedule); }, nextDate.getTime() - Date.now()); diff --git a/src/common/entities/job/JobProgressDTO.ts b/src/common/entities/job/JobProgressDTO.ts index a0a1ed71..efb17f20 100644 --- a/src/common/entities/job/JobProgressDTO.ts +++ b/src/common/entities/job/JobProgressDTO.ts @@ -28,3 +28,8 @@ export interface JobProgressDTO { end: number; }; } + + +export interface OnTimerJobProgressDTO extends JobProgressDTO { + onTimer?: boolean; // indicates if there is an active timer set for the job +} diff --git a/src/frontend/app/ui/settings/scheduled-jobs.service.ts b/src/frontend/app/ui/settings/scheduled-jobs.service.ts index dc5818ac..b290f3fa 100644 --- a/src/frontend/app/ui/settings/scheduled-jobs.service.ts +++ b/src/frontend/app/ui/settings/scheduled-jobs.service.ts @@ -1,6 +1,6 @@ import {EventEmitter, Injectable} from '@angular/core'; import {BehaviorSubject} from 'rxjs'; -import {JobProgressDTO, JobProgressStates,} from '../../../../common/entities/job/JobProgressDTO'; +import {JobProgressDTO, JobProgressStates, OnTimerJobProgressDTO,} from '../../../../common/entities/job/JobProgressDTO'; import {NetworkService} from '../../model/network/network.service'; import {JobScheduleDTO} from '../../../../common/entities/job/JobScheduleDTO'; import {ConfigTemplateEntry, JobDTO, JobDTOUtils} from '../../../../common/entities/job/JobDTO'; @@ -9,7 +9,7 @@ import {NotificationService} from '../../model/notification.service'; @Injectable() export class ScheduledJobsService { - public progress: BehaviorSubject>; + public progress: BehaviorSubject>; public onJobFinish: EventEmitter = new EventEmitter(); timer: number = null; public availableJobs: BehaviorSubject; diff --git a/src/frontend/app/ui/settings/workflow/button/job-button.settings.component.html b/src/frontend/app/ui/settings/workflow/button/job-button.settings.component.html index 612a4b78..06ce922a 100644 --- a/src/frontend/app/ui/settings/workflow/button/job-button.settings.component.html +++ b/src/frontend/app/ui/settings/workflow/button/job-button.settings.component.html @@ -1,4 +1,5 @@