@ -8,32 +8,28 @@ import { queryByMetric } from 'grafana-datasource-kit';
import * as _ from 'lodash' ;
import * as _ from 'lodash' ;
declare type UnitTime = {
type MetricDataChunk = { values : [ number , number ] [ ] , columns : string [ ] } ;
unit : AnalyticUnit.AnalyticUnit ,
time : number
const PULL_PERIOD_MS = 5000 ;
} ;
export class DataPuller {
export class DataPuller {
private PULL_PERIOD_MS : number = 5000 ;
private _unitTimes : { [ analyticUnitId : string ] : number } = { } ;
private _interval : number = 1000 ;
private _timer : any = null ;
private _unitTimes : { [ id : string ] : UnitTime } = { } ;
constructor ( private analyticsService : AnalyticsService ) { } ;
constructor ( private analyticsService : AnalyticsService ) { } ;
public addUnit ( unit : AnalyticUnit.AnalyticUnit ) {
public addUnit ( analyticUnit : AnalyticUnit.AnalyticUnit ) {
let time = unit . lastDetectionTime || Date . now ( ) ;
this . _runAnalyticUnitPuller ( analyticUnit ) ;
let unitTime : UnitTime = { unit , time } ;
this . _unitTimes [ unit . id ] = unitTime ;
}
}
public deleteUnit ( id : AnalyticUnit.AnalyticUnitId ) {
public deleteUnit ( analyticUnitId : AnalyticUnit.AnalyticUnitId ) {
delete this . _unitTimes [ id ] ;
if ( _ . has ( this . _unitTimes , analyticUnitId ) ) {
delete this . _unitTimes [ analyticUnitId ] ;
}
}
}
private pullData ( unit : AnalyticUnit.AnalyticUnit , from : number , to : number ) {
private async pullData ( unit : AnalyticUnit.AnalyticUnit , from : number , to : number ) : Promise < MetricDataChunk > {
if ( ! unit ) {
if ( unit === undefined ) {
throw Error ( ` puller: can't pull undefined unit ` ) ;
throw Error ( ` puller: can't pull undefined unit ` ) ;
}
}
return queryByMetric ( unit . metric , unit . panelUrl , from , to , HASTIC_API_KEY ) ;
return queryByMetric ( unit . metric , unit . panelUrl , from , to , HASTIC_API_KEY ) ;
@ -48,46 +44,65 @@ export class DataPuller {
}
}
//TODO: group analyticUnits by panelID and send same dataset for group
//TODO: group analyticUnits by panelID and send same dataset for group
public runPuller() {
public async runPuller() {
this . _timer = setTimeout ( this . puller . bind ( this ) , this . _interval ) ;
const analyticUnits = await AnalyticUnit . findMany ( { alert : true } ) ;
_ . each ( analyticUnits , analyticUnit = > {
this . _runAnalyticUnitPuller ( analyticUnit ) ;
} ) ;
console . log ( 'Data puller runned' ) ;
console . log ( 'Data puller runned' ) ;
}
}
public stopPuller() {
public stopPuller() {
if ( this . _timer ) {
this . _unitTimes = { } ;
clearTimeout ( this . _timer ) ;
this . _timer = null ;
this . _interval = 0 ;
console . log ( 'Data puller stopped' ) ;
}
console . log ( 'Data puller already stopped' ) ;
}
}
private async puller() {
private async _runAnalyticUnitPuller ( analyticUnit : AnalyticUnit.AnalyticUnit ) {
const time = analyticUnit . lastDetectionTime || Date . now ( ) ;
if ( _ . isEmpty ( this . _unitTimes ) ) {
this . _unitTimes [ analyticUnit . id ] = time ;
this . _interval = this . PULL_PERIOD_MS ;
this . _timer = setTimeout ( this . puller . bind ( this ) , this . _interval ) ;
return ;
}
let now = Date . now ( ) ;
const dataGenerator = this . getDataGenerator (
analyticUnit , PULL_PERIOD_MS
) ;
_ . forOwn ( this . _unitTimes , async value = > {
for await ( const data of dataGenerator ) {
if ( ! value . unit . alert ) {
if ( ! _ . has ( this . _unitTimes , analyticUnit . id ) ) {
return ;
break ;
}
}
let data = await this . pullData ( value . unit , value . time , now ) ;
if ( data . values . length === 0 ) {
if ( data . values . length === 0 ) {
return ;
continue ;
}
}
let payload = { data , from : value . time , to : now } ;
const now = Date . now ( ) ;
value . time = now ;
let payload = { data , from : time , to : now , pattern : analyticUnit.type } ;
this . pushData ( value . unit , payload ) ;
this . _unitTimes [ analyticUnit . id ] = now ;
} ) ;
this . pushData ( analyticUnit , payload ) ;
}
this . _timer = setTimeout ( this . puller . bind ( this ) , this . _interval ) ;
}
async * getDataGenerator ( analyticUnit : AnalyticUnit.AnalyticUnit , duration : number ) :
AsyncIterableIterator < MetricDataChunk > {
const getData = async ( ) = > {
try {
const time = this . _unitTimes [ analyticUnit . id ]
const now = Date . now ( ) ;
return await this . pullData ( analyticUnit , time , now ) ;
} catch ( err ) {
throw new Error ( ` Error while pulling data: ${ err . message } ` ) ;
}
}
const timeout = async ( ) = > new Promise (
resolve = > setTimeout ( resolve , duration )
) ;
while ( true ) {
yield await getData ( ) ;
await timeout ( ) ;
}
}
}
}
}