@@ -190,13 +190,15 @@ export class CpuUsageAlert extends BaseAlert {
190190 } ) ,
191191 nextSteps : [
192192 createLink (
193- 'xpack.monitoring.alerts.cpuUsage.ui.nextSteps.hotThreads' ,
194- 'Check hot threads' ,
193+ i18n . translate ( 'xpack.monitoring.alerts.cpuUsage.ui.nextSteps.hotThreads' , {
194+ defaultMessage : '#start_linkCheck hot threads#end_link' ,
195+ } ) ,
195196 `{elasticWebsiteUrl}/guide/en/elasticsearch/reference/{docLinkVersion}/cluster-nodes-hot-threads.html`
196197 ) ,
197198 createLink (
198- 'xpack.monitoring.alerts.cpuUsage.ui.nextSteps.runningTasks' ,
199- 'Check long running tasks' ,
199+ i18n . translate ( 'xpack.monitoring.alerts.cpuUsage.ui.nextSteps.runningTasks' , {
200+ defaultMessage : '#start_linkCheck long running tasks#end_link' ,
201+ } ) ,
200202 `{elasticWebsiteUrl}/guide/en/elasticsearch/reference/{docLinkVersion}/tasks.html`
201203 ) ,
202204 ] ,
@@ -338,49 +340,72 @@ export class CpuUsageAlert extends BaseAlert {
338340 clusters : AlertCluster [ ] ,
339341 services : AlertServices
340342 ) {
341- const currentUTC = + new Date ( ) ;
342343 for ( const cluster of clusters ) {
343- const nodes = data . filter ( ( node ) => node . clusterUuid === cluster . clusterUuid ) ;
344- if ( ! nodes . length ) {
344+ const nodes = data . filter ( ( _item ) => _item . clusterUuid === cluster . clusterUuid ) ;
345+ if ( nodes . length === 0 ) {
345346 continue ;
346347 }
347-
348- const instanceId = `.monitoring:${ this . type } :${ cluster . clusterUuid } ` ;
348+ const firingNodeUuids = nodes . reduce ( ( list : string [ ] , node ) => {
349+ const stat = node . meta as AlertCpuUsageNodeStats ;
350+ if ( node . shouldFire ) {
351+ list . push ( stat . nodeId ) ;
352+ }
353+ return list ;
354+ } , [ ] as string [ ] ) ;
355+ firingNodeUuids . sort ( ) ; // It doesn't matter how we sort, but keep the order consistent
356+ const instanceId = `${ this . type } :${ cluster . clusterUuid } :${ firingNodeUuids . join ( ',' ) } ` ;
349357 const instance = services . alertInstanceFactory ( instanceId ) ;
350- const state = instance . getState ( ) as AlertInstanceState ;
351- const newAlertStates : AlertInstanceState [ 'alertStates' ] = [ ] ;
352- const oldAlertStates = ( state ?. alertStates || [ ] ) as AlertCpuUsageState [ ] ;
353-
358+ const state = ( instance . getState ( ) as unknown ) as AlertInstanceState ;
359+ const alertInstanceState : AlertInstanceState = { alertStates : state ?. alertStates || [ ] } ;
360+ let shouldExecuteActions = false ;
354361 for ( const node of nodes ) {
355- const stat = node . meta as AlertCpuUsageState ;
356- const nodeState = this . getDefaultAlertState ( cluster , node ) as AlertCpuUsageState ;
362+ const stat = node . meta as AlertCpuUsageNodeStats ;
363+ let nodeState : AlertCpuUsageState ;
364+ const indexInState = alertInstanceState . alertStates . findIndex ( ( alertState ) => {
365+ const nodeAlertState = alertState as AlertCpuUsageState ;
366+ return (
367+ nodeAlertState . cluster . clusterUuid === cluster . clusterUuid &&
368+ nodeAlertState . nodeId === ( node . meta as AlertCpuUsageNodeStats ) . nodeId
369+ ) ;
370+ } ) ;
371+ if ( indexInState > - 1 ) {
372+ nodeState = alertInstanceState . alertStates [ indexInState ] as AlertCpuUsageState ;
373+ } else {
374+ nodeState = this . getDefaultAlertState ( cluster , node ) as AlertCpuUsageState ;
375+ }
357376 nodeState . cpuUsage = stat . cpuUsage ;
358377 nodeState . nodeId = stat . nodeId ;
359378 nodeState . nodeName = stat . nodeName ;
360379
361380 if ( node . shouldFire ) {
362- nodeState . ui . triggeredMS = currentUTC ;
381+ if ( ! nodeState . ui . isFiring ) {
382+ nodeState . ui . triggeredMS = new Date ( ) . valueOf ( ) ;
383+ }
363384 nodeState . ui . isFiring = true ;
385+ nodeState . ui . message = this . getUiMessage ( nodeState , node ) ;
364386 nodeState . ui . severity = node . severity ;
365- newAlertStates . push ( nodeState ) ;
366- } else {
367- const lastNodeState = oldAlertStates . find (
368- ( oldNodeState ) => nodeState . nodeId === oldNodeState . nodeId
369- ) ;
370- if ( lastNodeState ?. ui . isFiring ) {
371- nodeState . ui . resolvedMS = currentUTC ;
372- newAlertStates . push ( nodeState ) ;
373- }
387+ nodeState . ui . resolvedMS = 0 ;
388+ shouldExecuteActions = true ;
389+ } else if ( ! node . shouldFire && nodeState . ui . isFiring ) {
390+ nodeState . ui . isFiring = false ;
391+ nodeState . ui . resolvedMS = new Date ( ) . valueOf ( ) ;
392+ nodeState . ui . message = this . getUiMessage ( nodeState , node ) ;
393+ shouldExecuteActions = true ;
374394 }
375-
376- nodeState . ui . message = this . getUiMessage ( nodeState , node ) ;
377-
378- const alertInstanceState = { alertStates : newAlertStates } ;
379- instance . replaceState ( alertInstanceState ) ;
380- if ( newAlertStates . length && ! instance . hasScheduledActions ( ) ) {
381- this . executeActions ( instance , alertInstanceState , null , cluster ) ;
395+ if ( indexInState === - 1 ) {
396+ alertInstanceState . alertStates . push ( nodeState ) ;
397+ } else {
398+ alertInstanceState . alertStates = [
399+ ...alertInstanceState . alertStates . slice ( 0 , indexInState ) ,
400+ nodeState ,
401+ ...alertInstanceState . alertStates . slice ( indexInState + 1 ) ,
402+ ] ;
382403 }
383404 }
405+ instance . replaceState ( alertInstanceState ) ;
406+ if ( shouldExecuteActions ) {
407+ this . executeActions ( instance , alertInstanceState , null , cluster ) ;
408+ }
384409 }
385410 }
386411}
0 commit comments