mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-01-08 04:03:48 +02:00
Fix broken job scheduling. Also add UI indicator for active timer #725
This commit is contained in:
parent
eabb39d7b0
commit
55822c5cd8
@ -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();
|
||||
|
@ -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<T>(
|
||||
jobName: string,
|
||||
config: T,
|
||||
soloRun: boolean,
|
||||
allowParallelRun: boolean
|
||||
public async run<T>(
|
||||
jobName: string,
|
||||
config: T,
|
||||
soloRun: boolean,
|
||||
allowParallelRun: boolean
|
||||
): Promise<void> {
|
||||
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<unknown>,
|
||||
state: JobProgressStates,
|
||||
soloRun: boolean
|
||||
job: IJob<unknown>,
|
||||
state: JobProgressStates,
|
||||
soloRun: boolean
|
||||
): Promise<void> => {
|
||||
// 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<void> => {
|
||||
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());
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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<Record<string, JobProgressDTO>>;
|
||||
public progress: BehaviorSubject<Record<string, OnTimerJobProgressDTO>>;
|
||||
public onJobFinish: EventEmitter<string> = new EventEmitter<string>();
|
||||
timer: number = null;
|
||||
public availableJobs: BehaviorSubject<JobDTO[]>;
|
||||
|
@ -1,4 +1,5 @@
|
||||
<button class="btn {{danger ? 'btn-danger': 'btn-success'}}"
|
||||
[class.progress-bar-striped]="Progress?.onTimer"
|
||||
title="Trigger job run manually"
|
||||
i18n-title
|
||||
*ngIf="!Running"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
||||
import {JobProgressDTO, JobProgressStates,} from '../../../../../../common/entities/job/JobProgressDTO';
|
||||
import {JobProgressStates, OnTimerJobProgressDTO,} from '../../../../../../common/entities/job/JobProgressDTO';
|
||||
import {ErrorDTO} from '../../../../../../common/entities/Error';
|
||||
import {ScheduledJobsService} from '../../scheduled-jobs.service';
|
||||
import {NotificationService} from '../../../../model/notification.service';
|
||||
@ -23,9 +23,9 @@ export class JobButtonComponent {
|
||||
@Output() jobError = new EventEmitter<string>();
|
||||
|
||||
constructor(
|
||||
private notification: NotificationService,
|
||||
public jobsService: ScheduledJobsService,
|
||||
public backendTextService: BackendtextService
|
||||
private notification: NotificationService,
|
||||
public jobsService: ScheduledJobsService,
|
||||
public backendTextService: BackendtextService
|
||||
) {
|
||||
}
|
||||
|
||||
@ -41,17 +41,17 @@ export class JobButtonComponent {
|
||||
|
||||
public get Running(): boolean {
|
||||
return (
|
||||
this.Progress &&
|
||||
(this.Progress.state === JobProgressStates.running ||
|
||||
this.Progress.state === JobProgressStates.cancelling)
|
||||
this.Progress &&
|
||||
(this.Progress.state === JobProgressStates.running ||
|
||||
this.Progress.state === JobProgressStates.cancelling)
|
||||
);
|
||||
}
|
||||
|
||||
get Progress(): JobProgressDTO {
|
||||
get Progress(): OnTimerJobProgressDTO {
|
||||
this.populateConfig();
|
||||
return this.jobsService.progress.value[
|
||||
JobDTOUtils.getHashName(this.jobName, this.config)
|
||||
];
|
||||
JobDTOUtils.getHashName(this.jobName, this.config)
|
||||
];
|
||||
}
|
||||
|
||||
public async start(): Promise<boolean> {
|
||||
@ -59,15 +59,15 @@ export class JobButtonComponent {
|
||||
this.populateConfig();
|
||||
try {
|
||||
await this.jobsService.start(
|
||||
this.jobName,
|
||||
this.config,
|
||||
this.soloRun,
|
||||
this.allowParallelRun
|
||||
this.jobName,
|
||||
this.config,
|
||||
this.soloRun,
|
||||
this.allowParallelRun
|
||||
);
|
||||
this.notification.success(
|
||||
$localize`Job started` +
|
||||
': ' +
|
||||
this.backendTextService.getJobName(this.jobName)
|
||||
$localize`Job started` +
|
||||
': ' +
|
||||
this.backendTextService.getJobName(this.jobName)
|
||||
);
|
||||
return true;
|
||||
} catch (err) {
|
||||
@ -85,9 +85,9 @@ export class JobButtonComponent {
|
||||
try {
|
||||
await this.jobsService.stop(this.jobName);
|
||||
this.notification.info(
|
||||
$localize`Stopping job` +
|
||||
': ' +
|
||||
this.backendTextService.getJobName(this.jobName)
|
||||
$localize`Stopping job` +
|
||||
': ' +
|
||||
this.backendTextService.getJobName(this.jobName)
|
||||
);
|
||||
return true;
|
||||
} catch (err) {
|
||||
|
Loading…
Reference in New Issue
Block a user