library-ts/node/users/scheduler/Scheduler.ts

170 lines
3.8 KiB
TypeScript
Raw Normal View History

2025-11-15 18:58:30 +00:00
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';
2025-11-16 13:30:12 +00:00
import { DateFormatter } from '../../../browser/date/DateFormatter';
import { Duration } from '../../../browser/date/Duration';
2025-11-15 18:58:30 +00:00
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() );
2025-11-16 13:30:12 +00:00
RJLog.log( task.id, DateFormatter.HMS( task.date ), "delaying:", Duration.fromMilliSeconds( delay ) + " sec" );
2025-11-15 18:58:30 +00:00
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
);
}
2025-11-16 13:30:12 +00:00
cancelUserAppTask( taskID:string, userID:string, appID:string ):boolean
2025-11-15 18:58:30 +00:00
{
2025-11-16 13:30:12 +00:00
if ( ! taskID || ! userID || ! appID )
{
return false;
}
let index = this._queue.findIndex( e => e.id === taskID );
2025-11-15 18:58:30 +00:00
2025-11-16 13:30:12 +00:00
if ( index == -1 )
{
RJLog.log( "Task not found:", taskID );
return false;
}
let foundTask = this._queue[ index ];
if ( foundTask.userID !== userID || foundTask.appID !== appID )
{
RJLog.log( "Found task has not matching user:", foundTask.userID, foundTask.appID );
return false;
}
2025-11-15 18:58:30 +00:00
if ( index === -1 )
{
2025-11-16 13:30:12 +00:00
return false;
2025-11-15 18:58:30 +00:00
}
Arrays.removeAt( this._queue, index );
2025-11-16 13:30:12 +00:00
if ( taskID !== this._nextTaskID )
{
return true;
}
2025-11-15 18:58:30 +00:00
this._resetTimer();
this._updateTimer();
2025-11-16 13:30:12 +00:00
return true;
2025-11-15 18:58:30 +00:00
}
2025-11-16 13:30:12 +00:00
2025-11-15 18:58:30 +00:00
}