Change task id generation

Id must be generated sequentially
This commit is contained in:
Anton Vakhrushev 2020-04-18 21:47:05 +03:00
parent 3614624aa0
commit a6cc1b5383
8 changed files with 55 additions and 22 deletions

View File

@ -1,7 +1,7 @@
import { ActionController, registerAction } from './ActionController'; import { ActionController, registerAction } from './ActionController';
import { Args } from '../Common'; import { Args } from '../Common';
import { Task } from '../Storage/TaskQueue'; import { Task } from '../Storage/TaskQueue';
import { BuildingQueueFullError, GrabError } from '../Errors'; import { PostponeAllBuildingsError, GrabError } from '../Errors';
import { grabActiveVillageId, grabBuildingQueueInfo } from '../Page/VillageBlock'; import { grabActiveVillageId, grabBuildingQueueInfo } from '../Page/VillageBlock';
import { BuildingQueueInfo } from '../Game'; import { BuildingQueueInfo } from '../Game';
@ -10,7 +10,7 @@ export class CheckBuildingRemainingTimeAction extends ActionController {
async run(args: Args, task: Task): Promise<any> { async run(args: Args, task: Task): Promise<any> {
const info = this.grabBuildingQueueInfoOrDefault(); const info = this.grabBuildingQueueInfoOrDefault();
if (info.seconds > 0) { if (info.seconds > 0) {
throw new BuildingQueueFullError( throw new PostponeAllBuildingsError(
task.id, task.id,
grabActiveVillageId(), grabActiveVillageId(),
info.seconds + 1, info.seconds + 1,

View File

@ -1,17 +1,22 @@
import { ActionController, registerAction } from './ActionController'; import { ActionController, registerAction } from './ActionController';
import { Args } from '../Common'; import { Args } from '../Common';
import { GrabError, TryLaterError } from '../Errors'; import { ActionError, GrabError, PostponeAllBuildingsError } from '../Errors';
import { Task } from '../Storage/TaskQueue'; import { Task } from '../Storage/TaskQueue';
import { clickUpgradeButton } from '../Page/BuildingPage'; import { clickUpgradeButton } from '../Page/BuildingPage';
@registerAction @registerAction
export class UpgradeBuildingAction extends ActionController { export class UpgradeBuildingAction extends ActionController {
async run(args: Args, task: Task): Promise<any> { async run(args: Args, task: Task): Promise<any> {
let villageId = args.villageId;
if (villageId === undefined) {
throw new ActionError(task.id, 'No village id');
}
try { try {
clickUpgradeButton(); clickUpgradeButton();
} catch (e) { } catch (e) {
if (e instanceof GrabError) { if (e instanceof GrabError) {
throw new TryLaterError(task.id, 15 * 60, 'No upgrade button, try later'); throw new PostponeAllBuildingsError(task.id, villageId, 15 * 60, 'No upgrade button, try later');
} }
throw e; throw e;
} }

View File

@ -4,13 +4,13 @@
<div class="container"> <div class="container">
<table class="task-table"> <table class="task-table">
<tr v-for="task in shared.taskList" class="task-item" :class="{ 'this-village': isThisVillageTask(task) }"> <tr v-for="task in shared.taskList" class="task-item" :class="{ 'this-village': isThisVillageTask(task) }">
<td :title="formatDate(task.ts)">{{ formatDate(task.ts) }}</td> <td class="time-column" :title="formatDate(task.ts)">{{ formatDate(task.ts) }}</td>
<td :title="task.id">{{ task.id }}</td> <td class="id-column" :title="task.id">{{ task.id }}</td>
<td> <td class="actions-column">
<a href="#" title="Remove task" class="remove-action" v-on:click.prevent="onRemove(task.id)">&times;</a> <a href="#" title="Remove task" class="remove-action" v-on:click.prevent="onRemove(task.id)">&times;</a>
</td> </td>
<td :title="task.name">{{ task.name }}</td> <td class="name-column" :title="task.name">{{ task.name }}</td>
<td :title="JSON.stringify(task.args)">{{ JSON.stringify(task.args) }}</td> <td class="args-column" :title="JSON.stringify(task.args)">{{ JSON.stringify(task.args) }}</td>
</tr> </tr>
</table> </table>
</div> </div>
@ -66,8 +66,8 @@ export default {
} }
.task-item > td { .task-item > td {
border-top: 1px solid #ddd; border-top: 1px solid #ddd;
border-left: 1px solid #ddd;
padding: 2px 4px; padding: 2px 4px;
max-width: 25%;
} }
.this-village { .this-village {
color: blue; color: blue;
@ -76,4 +76,23 @@ export default {
font-weight: bold; font-weight: bold;
color: red; color: red;
} }
.time-column,
.actions-column {
max-width: 25%;
}
.id-column {
max-width: 80px;
overflow-x: hidden;
text-overflow: ellipsis;
}
.name-column {
max-width: 80px;
overflow-x: hidden;
text-overflow: ellipsis;
}
.args-column {
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
}
</style> </style>

View File

@ -51,11 +51,11 @@
<td></td> <td></td>
</tr> </tr>
<tr class="required-line"> <tr class="required-line">
<td class="right">Необх:</td> <td class="right">Профицит:</td>
<td class="right" v-text="village.lumber_need - village.lumber || ''"></td> <td class="right" v-text="village.lumber - village.lumber_need || ''"></td>
<td class="right" v-text="village.clay_need - village.clay || ''"></td> <td class="right" v-text="village.clay - village.clay_need || ''"></td>
<td class="right" v-text="village.iron_need - village.iron || ''"></td> <td class="right" v-text="village.iron - village.iron_need || ''"></td>
<td class="right" v-text="village.crop_need - village.crop || ''"></td> <td class="right" v-text="village.crop - village.crop_need || ''"></td>
<td></td> <td></td>
<td></td> <td></td>
</tr> </tr>

View File

@ -37,7 +37,7 @@ export class TryLaterError extends Error {
} }
} }
export class BuildingQueueFullError extends Error { export class PostponeAllBuildingsError extends Error {
readonly seconds: number; readonly seconds: number;
readonly villageId: number; readonly villageId: number;
readonly taskId: TaskId; readonly taskId: TaskId;
@ -47,6 +47,6 @@ export class BuildingQueueFullError extends Error {
this.villageId = villageId; this.villageId = villageId;
this.taskId = taskId; this.taskId = taskId;
this.seconds = seconds; this.seconds = seconds;
Object.setPrototypeOf(this, BuildingQueueFullError.prototype); Object.setPrototypeOf(this, PostponeAllBuildingsError.prototype);
} }
} }

View File

@ -1,5 +1,5 @@
import { markPage, sleepMicro, timestamp, waitForLoad } from './utils'; import { markPage, sleepMicro, timestamp, waitForLoad } from './utils';
import { AbortTaskError, ActionError, BuildingQueueFullError, TryLaterError } from './Errors'; import { AbortTaskError, ActionError, PostponeAllBuildingsError, TryLaterError } from './Errors';
import { Task } from './Storage/TaskQueue'; import { Task } from './Storage/TaskQueue';
import { Command } from './Common'; import { Command } from './Common';
import { TaskQueueRenderer } from './TaskQueueRenderer'; import { TaskQueueRenderer } from './TaskQueueRenderer';
@ -108,7 +108,7 @@ export class Executor {
return; return;
} }
if (err instanceof BuildingQueueFullError) { if (err instanceof PostponeAllBuildingsError) {
this.logger.warn('BUILDING QUEUE FULL, TRY ALL AFTER', err.seconds); this.logger.warn('BUILDING QUEUE FULL, TRY ALL AFTER', err.seconds);
this.scheduler.postponeBuildingsInVillage(err.villageId, err.seconds); this.scheduler.postponeBuildingsInVillage(err.villageId, err.seconds);
return; return;

View File

@ -8,8 +8,17 @@ const QUEUE_NAME = 'queue';
export type TaskId = string; export type TaskId = string;
let idSequence = 1;
let lastTimestamp = null;
function uniqTaskId(): TaskId { function uniqTaskId(): TaskId {
return uniqId(); const ts = Math.floor(Date.now() / 1000);
if (ts === lastTimestamp) {
++idSequence;
} else {
idSequence = 1;
}
return 'tid.' + ts + '.' + String(idSequence).padStart(4, '0') + '.' + uniqId('');
} }
export class Task { export class Task {

View File

@ -44,8 +44,8 @@ function generateId(count: number): string {
return str; return str;
} }
export function uniqId(): string { export function uniqId(prefix: string = 'id'): string {
return 'id' + generateId(6); return prefix + generateId(6);
} }
export function timestamp(): number { export function timestamp(): number {