mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* Alert doesn't fire action if it's muted or throttled
(cherry picked from commit e4dd6e769c
)
# Conflicts:
# x-pack/plugins/alerting/server/task_runner/task_runner.ts
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
c1302f903c
commit
0a67100f45
2 changed files with 148 additions and 28 deletions
|
@ -41,6 +41,7 @@ import { omit } from 'lodash';
|
|||
import { UntypedNormalizedRuleType } from '../rule_type_registry';
|
||||
import { ruleTypeRegistryMock } from '../rule_type_registry.mock';
|
||||
import { ExecuteOptions } from '../../../actions/server/create_execute_function';
|
||||
import moment from 'moment';
|
||||
|
||||
jest.mock('uuid', () => ({
|
||||
v4: () => '5f6aa57d-3e22-484e-bae8-cbed868f4d28',
|
||||
|
@ -978,7 +979,128 @@ describe('Task Runner', () => {
|
|||
}
|
||||
);
|
||||
|
||||
test('actionsPlugin.execute is not called when notifyWhen=onActionGroupChange and alert alert state does not change', async () => {
|
||||
test.each(ephemeralTestParams)(
|
||||
'skips firing actions for active alert if alert is throttled %s',
|
||||
async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction) => {
|
||||
(
|
||||
customTaskRunnerFactoryInitializerParams as TaskRunnerFactoryInitializerParamsType
|
||||
).actionsPlugin.isActionTypeEnabled.mockReturnValue(true);
|
||||
customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(
|
||||
true
|
||||
);
|
||||
actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse);
|
||||
ruleType.executor.mockImplementation(
|
||||
async ({
|
||||
services: executorServices,
|
||||
}: AlertExecutorOptions<
|
||||
AlertTypeParams,
|
||||
AlertTypeState,
|
||||
AlertInstanceState,
|
||||
AlertInstanceContext,
|
||||
string
|
||||
>) => {
|
||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
||||
executorServices.alertInstanceFactory('2').scheduleActions('default');
|
||||
}
|
||||
);
|
||||
const taskRunner = new TaskRunner(
|
||||
ruleType,
|
||||
{
|
||||
...mockedTaskInstance,
|
||||
state: {
|
||||
...mockedTaskInstance.state,
|
||||
alertInstances: {
|
||||
'2': {
|
||||
meta: {
|
||||
lastScheduledActions: { date: moment().toISOString(), group: 'default' },
|
||||
},
|
||||
state: {
|
||||
bar: false,
|
||||
start: '1969-12-31T00:00:00.000Z',
|
||||
duration: 86400000000000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
taskRunnerFactoryInitializerParams
|
||||
);
|
||||
rulesClient.get.mockResolvedValue({
|
||||
...mockedRuleTypeSavedObject,
|
||||
throttle: '1d',
|
||||
});
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
apiKey: Buffer.from('123:abc').toString('base64'),
|
||||
enabled: true,
|
||||
},
|
||||
references: [],
|
||||
});
|
||||
await taskRunner.run();
|
||||
// expect(enqueueFunction).toHaveBeenCalledTimes(1);
|
||||
|
||||
const logger = customTaskRunnerFactoryInitializerParams.logger;
|
||||
// expect(logger.debug).toHaveBeenCalledTimes(5);
|
||||
expect(logger.debug).nthCalledWith(
|
||||
3,
|
||||
`skipping scheduling of actions for '2' in rule test:1: 'rule-name': rule is throttled`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
test.each(ephemeralTestParams)(
|
||||
'skips firing actions for active alert when alert is muted even if notifyWhen === onActionGroupChange %s',
|
||||
async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction) => {
|
||||
customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(
|
||||
true
|
||||
);
|
||||
ruleType.executor.mockImplementation(
|
||||
async ({
|
||||
services: executorServices,
|
||||
}: AlertExecutorOptions<
|
||||
AlertTypeParams,
|
||||
AlertTypeState,
|
||||
AlertInstanceState,
|
||||
AlertInstanceContext,
|
||||
string
|
||||
>) => {
|
||||
executorServices.alertInstanceFactory('1').scheduleActions('default');
|
||||
executorServices.alertInstanceFactory('2').scheduleActions('default');
|
||||
}
|
||||
);
|
||||
const taskRunner = new TaskRunner(
|
||||
ruleType,
|
||||
mockedTaskInstance,
|
||||
customTaskRunnerFactoryInitializerParams
|
||||
);
|
||||
rulesClient.get.mockResolvedValue({
|
||||
...mockedRuleTypeSavedObject,
|
||||
mutedInstanceIds: ['2'],
|
||||
notifyWhen: 'onActionGroupChange',
|
||||
});
|
||||
encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue({
|
||||
id: '1',
|
||||
type: 'alert',
|
||||
attributes: {
|
||||
apiKey: Buffer.from('123:abc').toString('base64'),
|
||||
enabled: true,
|
||||
},
|
||||
references: [],
|
||||
});
|
||||
await taskRunner.run();
|
||||
expect(enqueueFunction).toHaveBeenCalledTimes(1);
|
||||
const logger = customTaskRunnerFactoryInitializerParams.logger;
|
||||
expect(logger.debug).toHaveBeenCalledTimes(5);
|
||||
expect(logger.debug).nthCalledWith(
|
||||
3,
|
||||
`skipping scheduling of actions for '2' in rule test:1: 'rule-name': rule is muted`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
test('actionsPlugin.execute is not called when notifyWhen=onActionGroupChange and alert state does not change', async () => {
|
||||
taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true);
|
||||
taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true);
|
||||
ruleType.executor.mockImplementation(
|
||||
|
|
|
@ -475,34 +475,32 @@ export class TaskRunner<
|
|||
|
||||
triggeredActions = concat(triggeredActions, scheduledActionsForRecoveredAlerts);
|
||||
|
||||
const alertsToExecute =
|
||||
notifyWhen === 'onActionGroupChange'
|
||||
? Object.entries(alertsWithScheduledActions).filter(
|
||||
([alertName, alert]: [string, AlertInstance<InstanceState, InstanceContext>]) => {
|
||||
const shouldExecuteAction = alert.scheduledActionGroupOrSubgroupHasChanged();
|
||||
if (!shouldExecuteAction) {
|
||||
this.logger.debug(
|
||||
`skipping scheduling of actions for '${alertName}' in rule ${ruleLabel}: alert is active but action group has not changed`
|
||||
);
|
||||
}
|
||||
return shouldExecuteAction;
|
||||
}
|
||||
)
|
||||
: Object.entries(alertsWithScheduledActions).filter(
|
||||
([alertName, alert]: [string, AlertInstance<InstanceState, InstanceContext>]) => {
|
||||
const throttled = alert.isThrottled(throttle);
|
||||
const muted = mutedAlertIdsSet.has(alertName);
|
||||
const shouldExecuteAction = !throttled && !muted;
|
||||
if (!shouldExecuteAction) {
|
||||
this.logger.debug(
|
||||
`skipping scheduling of actions for '${alertName}' in rule ${ruleLabel}: rule is ${
|
||||
muted ? 'muted' : 'throttled'
|
||||
}`
|
||||
);
|
||||
}
|
||||
return shouldExecuteAction;
|
||||
}
|
||||
const alertsToExecute = Object.entries(alertsWithScheduledActions).filter(
|
||||
([alertName, alert]: [string, AlertInstance<InstanceState, InstanceContext>]) => {
|
||||
const throttled = alert.isThrottled(throttle);
|
||||
const muted = mutedAlertIdsSet.has(alertName);
|
||||
let shouldExecuteAction = true;
|
||||
|
||||
if (throttled || muted) {
|
||||
shouldExecuteAction = false;
|
||||
this.logger.debug(
|
||||
`skipping scheduling of actions for '${alertName}' in rule ${ruleLabel}: rule is ${
|
||||
muted ? 'muted' : 'throttled'
|
||||
}`
|
||||
);
|
||||
} else if (
|
||||
notifyWhen === 'onActionGroupChange' &&
|
||||
!alert.scheduledActionGroupOrSubgroupHasChanged()
|
||||
) {
|
||||
shouldExecuteAction = false;
|
||||
this.logger.debug(
|
||||
`skipping scheduling of actions for '${alertName}' in rule ${ruleLabel}: alert is active but action group has not changed`
|
||||
);
|
||||
}
|
||||
|
||||
return shouldExecuteAction;
|
||||
}
|
||||
);
|
||||
|
||||
const allTriggeredActions = await Promise.all(
|
||||
alertsToExecute.map(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue