Clear task queue logic
This commit is contained in:
		| @@ -28,8 +28,8 @@ export class Scheduler { | ||||
|  | ||||
|     private scheduleUniqTask(seconds: number, name: string, args: Args = {}) { | ||||
|         const taskScheduler = () => { | ||||
|             if (!this.taskQueue.hasNamed(name)) { | ||||
|                 this.taskQueue.push(name, args, timestamp() + Math.min(seconds, 5 * 60)); | ||||
|             if (!this.taskQueue.has(t => t.name === name)) { | ||||
|                 this.scheduleTask(name, args, timestamp() + Math.min(seconds, 5 * 60)); | ||||
|             } | ||||
|         }; | ||||
|         taskScheduler(); | ||||
| @@ -48,23 +48,23 @@ export class Scheduler { | ||||
|         return this.actionQueue.pop(); | ||||
|     } | ||||
|  | ||||
|     scheduleTask(name: string, args: Args): void { | ||||
|         this.logger.log('PUSH TASK', name, args); | ||||
|     scheduleTask(name: string, args: Args, ts?: number | undefined): void { | ||||
|         this.logger.log('PUSH TASK', name, args, ts); | ||||
|         const villageId = args.villageId; | ||||
|         if (isBuildingTask(name)) { | ||||
|             this.taskQueue.insertAfterLast( | ||||
|             const insertedTs = calculateTimeToPushAfter( | ||||
|                 this.taskQueue.seeItems(), | ||||
|                 t => isBuildingTask(t.name) && sameVillage(villageId, t.args), | ||||
|                 name, | ||||
|                 args, | ||||
|                 timestamp() | ||||
|                 ts | ||||
|             ); | ||||
|             this.taskQueue.push(name, args, insertedTs); | ||||
|         } else { | ||||
|             this.taskQueue.push(name, args, timestamp()); | ||||
|             this.taskQueue.push(name, args, ts || timestamp()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     completeTask(id: TaskId) { | ||||
|         this.taskQueue.complete(id); | ||||
|         this.taskQueue.remove(id); | ||||
|         this.actionQueue.clear(); | ||||
|     } | ||||
|  | ||||
| @@ -74,13 +74,16 @@ export class Scheduler { | ||||
|     } | ||||
|  | ||||
|     postponeTask(id: TaskId, deltaTs: number) { | ||||
|         this.taskQueue.postpone(id, timestamp() + deltaTs); | ||||
|         this.taskQueue.modify( | ||||
|             t => t.id === id, | ||||
|             t => withTime(t, timestamp() + deltaTs) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     postponeBuildingsInVillage(villageId: number, seconds: number) { | ||||
|         this.taskQueue.modify( | ||||
|             t => isBuildingTask(t.name) && sameVillage(villageId, t.args), | ||||
|             t => t.withTime(timestamp() + seconds) | ||||
|             t => withTime(t, timestamp() + seconds) | ||||
|         ); | ||||
|     } | ||||
|  | ||||
| @@ -100,3 +103,29 @@ function isBuildingTask(taskName: string) { | ||||
| function sameVillage(villageId: number | undefined, args: Args) { | ||||
|     return villageId !== undefined && args.villageId === villageId; | ||||
| } | ||||
|  | ||||
| export function withTime(task: Task, ts: number): Task { | ||||
|     return new Task(task.id, ts, task.name, task.args); | ||||
| } | ||||
|  | ||||
| function calculateTimeToPushAfter(tasks: TaskList, predicate: (t: Task) => boolean, ts: number | undefined): number { | ||||
|     const normalizedTs = ts || timestamp(); | ||||
|     const queuedTaskIndex = findLastIndex(tasks, predicate); | ||||
|     if (queuedTaskIndex === undefined) { | ||||
|         return normalizedTs; | ||||
|     } | ||||
|     const queuedTask = tasks[queuedTaskIndex]; | ||||
|     return Math.max(normalizedTs, queuedTask.ts + 1); | ||||
| } | ||||
|  | ||||
| function findLastIndex(tasks: TaskList, predicate: (t: Task) => boolean): number | undefined { | ||||
|     const count = tasks.length; | ||||
|     const indexInReversed = tasks | ||||
|         .slice() | ||||
|         .reverse() | ||||
|         .findIndex(predicate); | ||||
|     if (indexInReversed < 0) { | ||||
|         return undefined; | ||||
|     } | ||||
|     return count - 1 - indexInReversed; | ||||
| } | ||||
|   | ||||
| @@ -23,10 +23,6 @@ export class Task { | ||||
|         this.name = name; | ||||
|         this.args = args; | ||||
|     } | ||||
|  | ||||
|     withTime(ts: number): Task { | ||||
|         return new Task(this.id, ts, this.name, this.args); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export type TaskList = Array<Task>; | ||||
| @@ -50,15 +46,6 @@ export class TaskQueue { | ||||
|         return task; | ||||
|     } | ||||
|  | ||||
|     insertAfterLast(predicate: (t: Task) => boolean, name: string, args: Args, ts: number): Task { | ||||
|         const id = uniqTaskId(); | ||||
|         const task = new Task(id, ts, name, args); | ||||
|         this.logger.log('INSERT AFTER TASK', id, ts, name, args); | ||||
|         const items = insertTaskAfter(task, this.getItems(), predicate); | ||||
|         this.flushItems(items); | ||||
|         return task; | ||||
|     } | ||||
|  | ||||
|     get(ts: number): Task | undefined { | ||||
|         const readyItems = this.getItems().filter(t => t.ts <= ts); | ||||
|         if (readyItems.length === 0) { | ||||
| @@ -72,30 +59,12 @@ export class TaskQueue { | ||||
|         return matched.length > 0; | ||||
|     } | ||||
|  | ||||
|     hasNamed(name: string): boolean { | ||||
|         return this.has(t => t.name === name); | ||||
|     } | ||||
|  | ||||
|     modify(predicate: (t: Task) => boolean, modifier: (t: Task) => Task) { | ||||
|         const [matched, other] = this.split(predicate); | ||||
|         const modified = matched.map(modifier); | ||||
|         this.flushItems(modified.concat(other)); | ||||
|     } | ||||
|  | ||||
|     complete(id: TaskId) { | ||||
|         const [_, items] = this.shiftTask(id); | ||||
|         this.flushItems(items); | ||||
|     } | ||||
|  | ||||
|     postpone(id: TaskId, newTs: number) { | ||||
|         const [task, items] = this.shiftTask(id); | ||||
|         if (task) { | ||||
|             this.logger.log('POSTPONE', task); | ||||
|             items.push(task.withTime(newTs)); | ||||
|         } | ||||
|         this.flushItems(items); | ||||
|     } | ||||
|  | ||||
|     remove(id: TaskId) { | ||||
|         const [_, items] = this.shiftTask(id); | ||||
|         this.flushItems(items); | ||||
| @@ -142,27 +111,3 @@ export class TaskQueue { | ||||
|         this.storage.set(QUEUE_NAME, normalized); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function insertTaskAfter(task: Task, tasks: TaskList, predicate: (t: Task) => boolean): TaskList { | ||||
|     const queuedTaskIndex = findLastIndex(tasks, predicate); | ||||
|     if (queuedTaskIndex === undefined) { | ||||
|         tasks.push(task); | ||||
|         return tasks; | ||||
|     } | ||||
|     const queuedTask = tasks[queuedTaskIndex]; | ||||
|     let insertedTask = task.withTime(Math.max(task.ts, queuedTask.ts + 1)); | ||||
|     tasks.splice(queuedTaskIndex, 0, insertedTask); | ||||
|     return tasks; | ||||
| } | ||||
|  | ||||
| function findLastIndex(tasks: TaskList, predicate: (t: Task) => boolean): number | undefined { | ||||
|     const count = tasks.length; | ||||
|     const indexInReversed = tasks | ||||
|         .slice() | ||||
|         .reverse() | ||||
|         .findIndex(predicate); | ||||
|     if (indexInReversed < 0) { | ||||
|         return undefined; | ||||
|     } | ||||
|     return count - 1 - indexInReversed; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user