141 lines
3.1 KiB
TypeScript
141 lines
3.1 KiB
TypeScript
|
|
import { MinPriorityQueue } from '@datastructures-js/priority-queue';
|
||
|
|
import { Arrays } from '../../../browser/tools/Arrays';
|
||
|
|
import { DateHelper } from '../../../browser/date/DateHelper';
|
||
|
|
import { DateMath } from '../../../browser/date/DateMath';
|
||
|
|
import { Task } from './Task';
|
||
|
|
import { iTaskScheduler } from './iTaskScheduler';
|
||
|
|
import { RJLog } from '../../log/RJLog';
|
||
|
|
|
||
|
|
export class Scheduler
|
||
|
|
{
|
||
|
|
// [ Tasks ]
|
||
|
|
_queue:Task[] = [];
|
||
|
|
_scheduledTasks = new Set<string>();
|
||
|
|
|
||
|
|
// [ Next Task ]
|
||
|
|
_taskTimerCallback:NodeJS.Timeout;
|
||
|
|
_nextTaskID:string;
|
||
|
|
|
||
|
|
// [ Settings ]
|
||
|
|
_maxScheduleDurationDays:number = 1;
|
||
|
|
|
||
|
|
// [ Schedulers ]
|
||
|
|
_taskSchedulers:iTaskScheduler[] = [];
|
||
|
|
get taskSchedulers(){ return this._taskSchedulers; }
|
||
|
|
|
||
|
|
constructor()
|
||
|
|
{
|
||
|
|
this._queue =[];
|
||
|
|
this._taskTimerCallback = null;
|
||
|
|
this._nextTaskID = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
get maxDate():Date
|
||
|
|
{
|
||
|
|
return DateMath.fromNowAddDays( this._maxScheduleDurationDays );
|
||
|
|
}
|
||
|
|
|
||
|
|
async update()
|
||
|
|
{
|
||
|
|
let maxDate = this.maxDate;
|
||
|
|
|
||
|
|
let allTasks:Task[] = [];
|
||
|
|
|
||
|
|
for ( let ts of this._taskSchedulers )
|
||
|
|
{
|
||
|
|
let tasks = await ts.getTasksToSchedule( maxDate );
|
||
|
|
allTasks = allTasks.concat( tasks );
|
||
|
|
}
|
||
|
|
|
||
|
|
this.scheduleTasks( allTasks );
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
scheduleTasks( tasks:Task[] )
|
||
|
|
{
|
||
|
|
let maxDate = DateMath.fromNowAddDays( this._maxScheduleDurationDays );
|
||
|
|
tasks = tasks.filter( t => ! this._scheduledTasks.has( t.id ) && ! DateMath.isAfter( t.date, maxDate ) );
|
||
|
|
|
||
|
|
|
||
|
|
this._queue = this._queue.concat( tasks );
|
||
|
|
tasks.forEach( t => this._scheduledTasks.add( t.id ) );
|
||
|
|
|
||
|
|
this._queue.sort( ( a, b ) => { return a.date.getTime() - b.date.getTime() } );
|
||
|
|
|
||
|
|
let newNextTask = this._queue[ 0 ];
|
||
|
|
|
||
|
|
if ( this._nextTaskID && newNextTask.id != this._nextTaskID )
|
||
|
|
{
|
||
|
|
this._resetTimer();
|
||
|
|
}
|
||
|
|
|
||
|
|
this._updateTimer();
|
||
|
|
}
|
||
|
|
|
||
|
|
protected _resetTimer()
|
||
|
|
{
|
||
|
|
if ( this._taskTimerCallback )
|
||
|
|
{
|
||
|
|
clearTimeout( this._taskTimerCallback );
|
||
|
|
this._taskTimerCallback = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
this._nextTaskID = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
protected _updateTimer()
|
||
|
|
{
|
||
|
|
// RJLog.log( "_updateTimer:" );
|
||
|
|
|
||
|
|
if ( this._taskTimerCallback || this._queue.length == 0 )
|
||
|
|
{
|
||
|
|
// RJLog.log( "Nothing to do. Has Timer:", this._taskTimerCallback, "Queue Length:", this._queue.length );
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
let task = this._queue[ 0 ];
|
||
|
|
this._nextTaskID = task.id;
|
||
|
|
|
||
|
|
let delay = Math.max( 0, task.date.getTime() - Date.now() );
|
||
|
|
|
||
|
|
RJLog.log( "delaying:", delay );
|
||
|
|
|
||
|
|
this._taskTimerCallback = setTimeout(
|
||
|
|
() =>
|
||
|
|
{
|
||
|
|
this._taskTimerCallback = null;
|
||
|
|
Arrays.remove( this._queue, task );
|
||
|
|
this._scheduledTasks.delete( task.id );
|
||
|
|
this._nextTaskID = null;
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
task.action();
|
||
|
|
}
|
||
|
|
catch( e )
|
||
|
|
{
|
||
|
|
RJLog.log( e );
|
||
|
|
}
|
||
|
|
|
||
|
|
this._updateTimer();
|
||
|
|
|
||
|
|
},
|
||
|
|
delay
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
cancelTask( id:string ): void
|
||
|
|
{
|
||
|
|
let index = this._queue.findIndex( e => e.id === id );
|
||
|
|
|
||
|
|
if ( index === -1 )
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
Arrays.removeAt( this._queue, index );
|
||
|
|
|
||
|
|
this._resetTimer();
|
||
|
|
this._updateTimer();
|
||
|
|
}
|
||
|
|
}
|