Skip to content

Commit

Permalink
[Response Ops][Alerting] Refactor ExecutionHandler stage 2 (#193807)
Browse files Browse the repository at this point in the history
Resolves #186534

## Summary

This PR splits the for-loop in the `ActionScheduler.run` function into
the appropriate scheduler classes. Previously, each scheduler had a
`generateExecutables` function that would return an array of executables
and the `ActionScheduler` would loop through the array and convert the
executable to a scheduleable action depending on whether it was a
per-alert action, summary action or system action. This refactor renames
`generateExecutables` into `getActionsToSchedule` and moves the logic to
convert the executables into a schedulable action into the appropriate
scheduler class.

## To Verify

Create some rules with per-alert and summary and system actions and
verify they are triggered as expected.

---------

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
ymao1 and elasticmachine authored Oct 9, 2024
1 parent 554ec2e commit 9221ab1
Show file tree
Hide file tree
Showing 26 changed files with 2,287 additions and 829 deletions.
90 changes: 90 additions & 0 deletions x-pack/plugins/actions/server/create_execute_function.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,7 @@ describe('bulkExecute()', () => {
"actionTypeId": "mock-action",
"id": "123",
"response": "queuedActionsLimitError",
"uuid": undefined,
},
],
}
Expand All @@ -1099,4 +1100,93 @@ describe('bulkExecute()', () => {
]
`);
});

test('passes through action uuid if provided', async () => {
mockTaskManager.aggregate.mockResolvedValue({
took: 1,
timed_out: false,
_shards: { total: 1, successful: 1, skipped: 0, failed: 0 },
hits: { total: { value: 2, relation: 'eq' }, max_score: null, hits: [] },
aggregations: {},
});
mockActionsConfig.getMaxQueued.mockReturnValueOnce(3);
const executeFn = createBulkExecutionEnqueuerFunction({
taskManager: mockTaskManager,
actionTypeRegistry: actionTypeRegistryMock.create(),
isESOCanEncrypt: true,
inMemoryConnectors: [],
configurationUtilities: mockActionsConfig,
logger: mockLogger,
});
savedObjectsClient.bulkGet.mockResolvedValueOnce({
saved_objects: [
{ id: '123', type: 'action', attributes: { actionTypeId: 'mock-action' }, references: [] },
],
});
savedObjectsClient.bulkCreate.mockResolvedValueOnce({
saved_objects: [
{ id: '234', type: 'action_task_params', attributes: { actionId: '123' }, references: [] },
],
});
expect(
await executeFn(savedObjectsClient, [
{
id: '123',
params: { baz: false },
spaceId: 'default',
executionId: '123abc',
apiKey: null,
source: asHttpRequestExecutionSource(request),
actionTypeId: 'mock-action',
uuid: 'aaa',
},
{
id: '123',
params: { baz: false },
spaceId: 'default',
executionId: '456xyz',
apiKey: null,
source: asHttpRequestExecutionSource(request),
actionTypeId: 'mock-action',
uuid: 'bbb',
},
])
).toMatchInlineSnapshot(`
Object {
"errors": true,
"items": Array [
Object {
"actionTypeId": "mock-action",
"id": "123",
"response": "success",
"uuid": "aaa",
},
Object {
"actionTypeId": "mock-action",
"id": "123",
"response": "queuedActionsLimitError",
"uuid": "bbb",
},
],
}
`);
expect(mockTaskManager.bulkSchedule).toHaveBeenCalledTimes(1);
expect(mockTaskManager.bulkSchedule.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Array [
Object {
"params": Object {
"actionTaskParamsId": "234",
"spaceId": "default",
},
"scope": Array [
"actions",
],
"state": Object {},
"taskType": "actions:mock-action",
},
],
]
`);
});
});
4 changes: 4 additions & 0 deletions x-pack/plugins/actions/server/create_execute_function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface CreateExecuteFunctionOptions {
export interface ExecuteOptions
extends Pick<ActionExecutorOptions, 'params' | 'source' | 'relatedSavedObjects' | 'consumer'> {
id: string;
uuid?: string;
spaceId: string;
apiKey: string | null;
executionId: string;
Expand Down Expand Up @@ -71,6 +72,7 @@ export interface ExecutionResponse {

export interface ExecutionResponseItem {
id: string;
uuid?: string;
actionTypeId: string;
response: ExecutionResponseType;
}
Expand Down Expand Up @@ -197,12 +199,14 @@ export function createBulkExecutionEnqueuerFunction({
items: runnableActions
.map((a) => ({
id: a.id,
uuid: a.uuid,
actionTypeId: a.actionTypeId,
response: ExecutionResponseType.SUCCESS,
}))
.concat(
actionsOverLimit.map((a) => ({
id: a.id,
uuid: a.uuid,
actionTypeId: a.actionTypeId,
response: ExecutionResponseType.QUEUED_ACTIONS_LIMIT_ERROR,
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,15 @@ describe('AlertingEventLogger', () => {

expect(eventLogger.logEvent).toHaveBeenCalledWith(event);
});

test('should log action event with uuid', () => {
alertingEventLogger.initialize({ context: ruleContext, runDate, ruleData });
alertingEventLogger.logAction({ ...action, uuid: 'abcdefg' });

const event = createActionExecuteRecord(ruleContext, ruleData, [alertSO], action);

expect(eventLogger.logEvent).toHaveBeenCalledWith(event);
});
});

describe('done()', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ interface AlertOpts {

export interface ActionOpts {
id: string;
// uuid is typed as optional but in reality it is always
// populated - https://github.com/elastic/kibana/issues/195255
uuid?: string;
typeId: string;
alertId?: string;
alertGroup?: string;
Expand Down
Loading

0 comments on commit 9221ab1

Please sign in to comment.