mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -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.test.ts
# x-pack/plugins/alerting/server/task_runner/task_runner.ts
This commit is contained in:
parent
bbefaf052e
commit
4313930141
2 changed files with 163 additions and 35 deletions
|
@ -40,6 +40,7 @@ import { omit } from 'lodash';
|
|||
import { UntypedNormalizedAlertType } from '../rule_type_registry';
|
||||
import { ruleTypeRegistryMock } from '../rule_type_registry.mock';
|
||||
import { ExecuteOptions } from '../../../actions/server/create_execute_function';
|
||||
import moment from 'moment';
|
||||
|
||||
const alertType: jest.Mocked<UntypedNormalizedAlertType> = {
|
||||
id: 'test',
|
||||
|
@ -55,6 +56,10 @@ const alertType: jest.Mocked<UntypedNormalizedAlertType> = {
|
|||
|
||||
let fakeTimer: sinon.SinonFakeTimers;
|
||||
|
||||
export const mockRunNowResponse = {
|
||||
id: 1,
|
||||
} as jest.ResolvedValue<unknown>;
|
||||
|
||||
describe('Task Runner', () => {
|
||||
let mockedTaskInstance: ConcreteTaskInstance;
|
||||
|
||||
|
@ -865,7 +870,136 @@ describe('Task Runner', () => {
|
|||
}
|
||||
);
|
||||
|
||||
test('actionsPlugin.execute is not called when notifyWhen=onActionGroupChange and alert instance state does not change', async () => {
|
||||
testAgainstEphemeralSupport(
|
||||
'skips firing actions for active alert if alert is throttled %s',
|
||||
(
|
||||
customTaskRunnerFactoryInitializerParams: TaskRunnerFactoryInitializerParamsType,
|
||||
enqueueFunction: (options: ExecuteOptions) => Promise<void | RunNowResult>
|
||||
) =>
|
||||
async () => {
|
||||
(
|
||||
customTaskRunnerFactoryInitializerParams as TaskRunnerFactoryInitializerParamsType
|
||||
).actionsPlugin.isActionTypeEnabled.mockReturnValue(true);
|
||||
customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(
|
||||
true
|
||||
);
|
||||
actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse);
|
||||
alertType.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(
|
||||
alertType,
|
||||
{
|
||||
...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({
|
||||
...mockedAlertTypeSavedObject,
|
||||
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(4);
|
||||
expect(logger.debug).nthCalledWith(
|
||||
3,
|
||||
`skipping scheduling of actions for '2' in alert test:1: 'alert-name': instance is throttled`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
testAgainstEphemeralSupport(
|
||||
'skips firing actions for active alert when alert is muted even if notifyWhen === onActionGroupChange %s',
|
||||
(
|
||||
customTaskRunnerFactoryInitializerParams: TaskRunnerFactoryInitializerParamsType,
|
||||
enqueueFunction: (options: ExecuteOptions) => Promise<void | RunNowResult>
|
||||
) =>
|
||||
async () => {
|
||||
customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(
|
||||
true
|
||||
);
|
||||
alertType.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(
|
||||
alertType,
|
||||
mockedTaskInstance,
|
||||
customTaskRunnerFactoryInitializerParams
|
||||
);
|
||||
rulesClient.get.mockResolvedValue({
|
||||
...mockedAlertTypeSavedObject,
|
||||
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(4);
|
||||
expect(logger.debug).nthCalledWith(
|
||||
3,
|
||||
`skipping scheduling of actions for '2' in alert test:1: 'alert-name': instance 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);
|
||||
alertType.executor.mockImplementation(
|
||||
|
|
|
@ -379,41 +379,35 @@ export class TaskRunner<
|
|||
alertLabel,
|
||||
});
|
||||
|
||||
const instancesToExecute =
|
||||
notifyWhen === 'onActionGroupChange'
|
||||
? Object.entries(instancesWithScheduledActions).filter(
|
||||
([alertInstanceName, alertInstance]: [
|
||||
string,
|
||||
AlertInstance<InstanceState, InstanceContext>
|
||||
]) => {
|
||||
const shouldExecuteAction =
|
||||
alertInstance.scheduledActionGroupOrSubgroupHasChanged();
|
||||
if (!shouldExecuteAction) {
|
||||
this.logger.debug(
|
||||
`skipping scheduling of actions for '${alertInstanceName}' in alert ${alertLabel}: instance is active but action group has not changed`
|
||||
);
|
||||
}
|
||||
return shouldExecuteAction;
|
||||
}
|
||||
)
|
||||
: Object.entries(instancesWithScheduledActions).filter(
|
||||
([alertInstanceName, alertInstance]: [
|
||||
string,
|
||||
AlertInstance<InstanceState, InstanceContext>
|
||||
]) => {
|
||||
const throttled = alertInstance.isThrottled(throttle);
|
||||
const muted = mutedInstanceIdsSet.has(alertInstanceName);
|
||||
const shouldExecuteAction = !throttled && !muted;
|
||||
if (!shouldExecuteAction) {
|
||||
this.logger.debug(
|
||||
`skipping scheduling of actions for '${alertInstanceName}' in alert ${alertLabel}: instance is ${
|
||||
muted ? 'muted' : 'throttled'
|
||||
}`
|
||||
);
|
||||
}
|
||||
return shouldExecuteAction;
|
||||
}
|
||||
const instancesToExecute = Object.entries(instancesWithScheduledActions).filter(
|
||||
([alertInstanceName, alertInstance]: [
|
||||
string,
|
||||
AlertInstance<InstanceState, InstanceContext>
|
||||
]) => {
|
||||
const throttled = alertInstance.isThrottled(throttle);
|
||||
const muted = mutedInstanceIdsSet.has(alertInstanceName);
|
||||
let shouldExecuteAction = true;
|
||||
|
||||
if (throttled || muted) {
|
||||
shouldExecuteAction = false;
|
||||
this.logger.debug(
|
||||
`skipping scheduling of actions for '${alertInstanceName}' in alert ${alertLabel}: instance is ${
|
||||
muted ? 'muted' : 'throttled'
|
||||
}`
|
||||
);
|
||||
} else if (
|
||||
notifyWhen === 'onActionGroupChange' &&
|
||||
!alertInstance.scheduledActionGroupOrSubgroupHasChanged()
|
||||
) {
|
||||
shouldExecuteAction = false;
|
||||
this.logger.debug(
|
||||
`skipping scheduling of actions for '${alertInstanceName}' in alert ${alertLabel}: instance is active but action group has not changed`
|
||||
);
|
||||
}
|
||||
|
||||
return shouldExecuteAction;
|
||||
}
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
instancesToExecute.map(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue