Clear task queue logic

This commit is contained in:
Anton Vakhrushev 2020-04-18 16:00:19 +03:00
parent 57ccf14553
commit 236135f1ca
2 changed files with 41 additions and 67 deletions

View File

@ -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;
}

View File

@ -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;
}