Fix statistics records trimming
This commit is contained in:
		| @@ -5,6 +5,8 @@ import { ActionQueue } from './Queue/ActionQueue'; | ||||
| import { Executor } from './Executor'; | ||||
| import { ControlPanel } from './ControlPanel'; | ||||
| import { DataStorageTaskProvider } from './Queue/DataStorageTaskProvider'; | ||||
| import { Statistics } from './Statistics'; | ||||
| import { StatisticsStorage } from './Storage/StatisticsStorage'; | ||||
|  | ||||
| export class Container { | ||||
|     private readonly version: string; | ||||
| @@ -33,7 +35,7 @@ export class Container { | ||||
|         this._executor = | ||||
|             this._executor || | ||||
|             (() => { | ||||
|                 return new Executor(this.version, this.scheduler); | ||||
|                 return new Executor(this.version, this.scheduler, this.statistics); | ||||
|             })(); | ||||
|         return this._executor; | ||||
|     } | ||||
| @@ -48,4 +50,15 @@ export class Container { | ||||
|             })(); | ||||
|         return this._controlPanel; | ||||
|     } | ||||
|  | ||||
|     private _statistics: Statistics | undefined; | ||||
|  | ||||
|     get statistics(): Statistics { | ||||
|         this._statistics = | ||||
|             this._statistics || | ||||
|             (() => { | ||||
|                 return new Statistics(new StatisticsStorage()); | ||||
|             })(); | ||||
|         return this._statistics; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -23,11 +23,11 @@ export class Executor { | ||||
|     private executionState: ExecutionStorage; | ||||
|     private logger: Logger; | ||||
|  | ||||
|     constructor(version: string, scheduler: Scheduler) { | ||||
|     constructor(version: string, scheduler: Scheduler, statistics: Statistics) { | ||||
|         this.version = version; | ||||
|         this.scheduler = scheduler; | ||||
|         this.grabbers = new GrabberManager(); | ||||
|         this.statistics = new Statistics(); | ||||
|         this.statistics = statistics; | ||||
|         this.executionState = new ExecutionStorage(); | ||||
|         this.logger = new ConsoleLogger(this.constructor.name); | ||||
|     } | ||||
| @@ -103,7 +103,7 @@ export class Executor { | ||||
|             throw new ActionError(`Action task id ${cmd.args.taskId} not equal current task id ${task.id}`); | ||||
|         } | ||||
|         if (actionHandler) { | ||||
|             this.statistics.incrementAction(); | ||||
|             this.statistics.incrementAction(timestamp()); | ||||
|             await actionHandler.run(cmd.args, task); | ||||
|         } else { | ||||
|             this.logger.warn('ACTION NOT FOUND', cmd.name); | ||||
|   | ||||
| @@ -1,25 +1,54 @@ | ||||
| import { StatisticsStorage } from './Storage/StatisticsStorage'; | ||||
| import * as dateFormat from 'dateformat'; | ||||
|  | ||||
| const KEY_FORMAT = 'yyyy-mm-dd-HH'; | ||||
| const KEEP_RECORD_COUNT = 24; | ||||
|  | ||||
| export interface ActionStatistics { | ||||
|     [key: string]: number; | ||||
| } | ||||
|  | ||||
| export class Statistics { | ||||
|     private state: StatisticsStorage; | ||||
| export interface StatisticsStorageInterface { | ||||
|     getActionStatistics(): ActionStatistics; | ||||
|     setActionStatistics(statistics: ActionStatistics): void; | ||||
| } | ||||
|  | ||||
|     constructor() { | ||||
|         this.state = new StatisticsStorage(); | ||||
| export class Statistics { | ||||
|     private state: StatisticsStorageInterface; | ||||
|  | ||||
|     static readonly keepRecords = KEEP_RECORD_COUNT; | ||||
|  | ||||
|     constructor(storage: StatisticsStorageInterface) { | ||||
|         this.state = storage; | ||||
|     } | ||||
|  | ||||
|     incrementAction(): void { | ||||
|     incrementAction(ts: number): void { | ||||
|         const stat = this.state.getActionStatistics(); | ||||
|         const key = dateFormat(Date.now(), 'yyyy-mm-dd-HH'); | ||||
|         const key = dateFormat(ts * 1000, KEY_FORMAT); | ||||
|         stat[key] = (stat[key] || 0) + 1; | ||||
|         this.trimStatistics(stat); | ||||
|         this.state.setActionStatistics(stat); | ||||
|     } | ||||
|  | ||||
|     private trimStatistics(stat: ActionStatistics) { | ||||
|         const topKeys = this.getTopStatKeys(stat); | ||||
|         const statKeys = Object.keys(stat); | ||||
|         for (let key of statKeys) { | ||||
|             if (!topKeys.includes(key)) { | ||||
|                 delete stat[key]; | ||||
|             } | ||||
|         } | ||||
|         return stat; | ||||
|     } | ||||
|  | ||||
|     private getTopStatKeys(stat: ActionStatistics) { | ||||
|         const keys = Object.keys(stat); | ||||
|         return keys | ||||
|             .sort() | ||||
|             .reverse() | ||||
|             .slice(0, KEEP_RECORD_COUNT); | ||||
|     } | ||||
|  | ||||
|     getActionStatistics(): ActionStatistics { | ||||
|         return {}; | ||||
|         return this.state.getActionStatistics(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| import { DataStorage } from '../DataStorage'; | ||||
| import { ActionStatistics } from '../Statistics'; | ||||
| import { ActionStatistics, StatisticsStorageInterface } from '../Statistics'; | ||||
|  | ||||
| const NAMESPACE = 'statistics.v1'; | ||||
|  | ||||
| const ACTION_STATISTICS_KEY = 'actions'; | ||||
|  | ||||
| export class StatisticsStorage { | ||||
| export class StatisticsStorage implements StatisticsStorageInterface { | ||||
|     private storage: DataStorage; | ||||
|     constructor() { | ||||
|         this.storage = new DataStorage(NAMESPACE); | ||||
|   | ||||
| @@ -115,6 +115,10 @@ export function notify(msg: string): void { | ||||
|     setTimeout(() => n && n.close(), 4000); | ||||
| } | ||||
|  | ||||
| export interface NowTimeGenerator { | ||||
|     (): number; | ||||
| } | ||||
|  | ||||
| export function markPage(text: string, version: string) { | ||||
|     jQuery('body').append( | ||||
|         '<div style="' + | ||||
|   | ||||
		Reference in New Issue
	
	Block a user