From b95bccdeb66ddef74b916c2e21430d080b67c0f1 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 22 Feb 2023 09:27:53 -0500 Subject: [PATCH 01/17] Remove tasks instead of marking them as failed --- .../server/task_running/task_runner.test.ts | 30 +++++++------------ .../server/task_running/task_runner.ts | 18 ++++++----- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts index b66f4bc418640..14da1bc46bab2 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts @@ -957,7 +957,7 @@ describe('TaskManagerRunner', () => { expect(store.update).toHaveBeenCalledWith(expect.objectContaining({ runAt })); }); - test(`doesn't reschedule recurring tasks that throw an unrecoverable error`, async () => { + test(`Removes recurring tasks that throw an unrecoverable error`, async () => { const id = _.random(1, 20).toString(); const error = new Error('Dangit!'); const onTaskEvent = jest.fn(); @@ -988,9 +988,8 @@ describe('TaskManagerRunner', () => { await runner.run(); - const instance = store.update.mock.calls[0][0]; - expect(instance.status).toBe('failed'); - expect(instance.enabled).not.toBeDefined(); + expect(store.remove).toHaveBeenCalledWith(id); + expect(store.update).not.toHaveBeenCalled(); expect(onTaskEvent).toHaveBeenCalledWith( withAnyTiming( @@ -1201,12 +1200,9 @@ describe('TaskManagerRunner', () => { await runner.run(); - expect(store.update).toHaveBeenCalledTimes(1); + expect(store.remove).toHaveBeenCalledWith(id); + expect(store.update).not.toHaveBeenCalled(); sinon.assert.calledWith(getRetryStub, initialAttempts, error); - const instance = store.update.mock.calls[0][0]; - - expect(instance.status).toBe('failed'); - expect(instance.enabled).not.toBeDefined(); }); test('bypasses getRetry function (returning false) on error of a recurring task', async () => { @@ -1247,7 +1243,7 @@ describe('TaskManagerRunner', () => { expect(instance.enabled).not.toBeDefined(); }); - test('Fails non-recurring task when maxAttempts reached', async () => { + test('Removes non-recurring task when maxAttempts reached', async () => { const id = _.random(1, 20).toString(); const initialAttempts = 3; const { runner, store } = await readyToRunStageSetup({ @@ -1272,13 +1268,8 @@ describe('TaskManagerRunner', () => { await runner.run(); - expect(store.update).toHaveBeenCalledTimes(1); - const instance = store.update.mock.calls[0][0]; - expect(instance.attempts).toEqual(3); - expect(instance.status).toEqual('failed'); - expect(instance.retryAt!).toBeNull(); - expect(instance.runAt.getTime()).toBeLessThanOrEqual(Date.now()); - expect(instance.enabled).not.toBeDefined(); + expect(store.remove).toHaveBeenCalledWith(id); + expect(store.update).not.toHaveBeenCalled(); }); test(`Doesn't fail recurring tasks when maxAttempts reached`, async () => { @@ -1502,9 +1493,8 @@ describe('TaskManagerRunner', () => { await runner.run(); - const instance = store.update.mock.calls[0][0]; - expect(instance.status).toBe('failed'); - expect(instance.enabled).not.toBeDefined(); + expect(store.remove).toHaveBeenCalledWith(id); + expect(store.update).not.toHaveBeenCalled(); expect(onTaskEvent).toHaveBeenCalledWith( withAnyTiming( diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.ts index 62bc9d4f19734..95d0105d10685 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.ts @@ -536,7 +536,17 @@ export class TaskManagerRunner implements TaskRunner { unwrap )(result); - if (!this.isExpired) { + if (this.isExpired) { + this.usageCounter?.incrementCounter({ + counterName: `taskManagerUpdateSkippedDueToTaskExpiration`, + counterType: 'taskManagerTaskRunner', + incrementBy: 1, + }); + } else if (fieldUpdates.status === TaskStatus.Failed) { + // Delete the SO instead so it doesn't remain in the index forever + await this.bufferedTaskStore.remove(this.id); + asRan(this.instance.task); + } else { this.instance = asRan( await this.bufferedTaskStore.update( defaults( @@ -551,12 +561,6 @@ export class TaskManagerRunner implements TaskRunner { ) ) ); - } else { - this.usageCounter?.incrementCounter({ - counterName: `taskManagerUpdateSkippedDueToTaskExpiration`, - counterType: 'taskManagerTaskRunner', - incrementBy: 1, - }); } return fieldUpdates.status === TaskStatus.Failed From 9840419668062f0dd1483e7d7ca276b9d62f7108 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 7 Mar 2023 12:37:48 -0500 Subject: [PATCH 02/17] Initial commit --- .../actions/server/lib/task_runner_factory.ts | 111 ++++++------------ x-pack/plugins/actions/server/plugin.ts | 5 +- .../mark_available_tasks_as_claimed.ts | 1 + x-pack/plugins/task_manager/server/task.ts | 1 + .../server/task_running/task_runner.ts | 20 +++- 5 files changed, 59 insertions(+), 79 deletions(-) diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index d5b82e8fc6f6e..d16ff88ed6e75 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -12,14 +12,13 @@ import { map, fromNullable, getOrElse } from 'fp-ts/lib/Option'; import { addSpaceIdToPath } from '@kbn/spaces-plugin/server'; import { Logger, - SavedObjectsClientContract, - KibanaRequest, CoreKibanaRequest, SavedObjectReference, IBasePath, SavedObject, Headers, FakeRawRequest, + ISavedObjectsRepository, } from '@kbn/core/server'; import { RunContext } from '@kbn/task-manager-plugin/server'; import { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server'; @@ -45,7 +44,7 @@ export interface TaskRunnerContext { encryptedSavedObjectsClient: EncryptedSavedObjectsClient; spaceIdToNamespace: SpaceIdToNamespaceFunction; basePathService: IBasePath; - getUnsecuredSavedObjectsClient: (request: KibanaRequest) => SavedObjectsClientContract; + savedObjectsRepository: ISavedObjectsRepository; } export class TaskRunnerFactory { @@ -67,7 +66,7 @@ export class TaskRunnerFactory { this.taskRunnerContext = taskRunnerContext; } - public create({ taskInstance }: RunContext, maxAttempts: number = 1) { + public create({ taskInstance }: RunContext) { if (!this.isInitialized) { throw new Error('TaskRunnerFactory not initialized'); } @@ -78,7 +77,7 @@ export class TaskRunnerFactory { encryptedSavedObjectsClient, spaceIdToNamespace, basePathService, - getUnsecuredSavedObjectsClient, + savedObjectsRepository, } = this.taskRunnerContext!; const taskInfo = { @@ -86,10 +85,10 @@ export class TaskRunnerFactory { attempts: taskInstance.attempts, }; const actionExecutionId = uuidv4(); + const actionTaskExecutorParams = taskInstance.params as ActionTaskExecutorParams; return { async run() { - const actionTaskExecutorParams = taskInstance.params as ActionTaskExecutorParams; const { spaceId } = actionTaskExecutorParams; const { @@ -105,53 +104,22 @@ export class TaskRunnerFactory { const request = getFakeRequest(apiKey); basePathService.set(request, path); - // Throwing an executor error means we will attempt to retry the task - // TM will treat a task as a failure if `attempts >= maxAttempts` - // so we need to handle that here to avoid TM persisting the failed task - const isRetryableBasedOnAttempts = taskInfo.attempts < maxAttempts; - const willRetryMessage = `and will retry`; - const willNotRetryMessage = `and will not retry`; - - let executorResult: ActionTypeExecutorResult | undefined; - try { - executorResult = await actionExecutor.execute({ - params, - actionId: actionId as string, - isEphemeral: !isPersistedActionTask(actionTaskExecutorParams), - request, - ...getSourceFromReferences(references), - taskInfo, - executionId, - consumer, - relatedSavedObjects: validatedRelatedSavedObjects(logger, relatedSavedObjects), - actionExecutionId, - }); - } catch (e) { - logger.error( - `Action '${actionId}' failed ${ - isRetryableBasedOnAttempts ? willRetryMessage : willNotRetryMessage - }: ${e.message}` - ); - if (isRetryableBasedOnAttempts) { - // In order for retry to work, we need to indicate to task manager this task - // failed - throw new ExecutorError(e.message, {}, true); - } - } + const executorResult: ActionTypeExecutorResult = await actionExecutor.execute({ + params, + actionId: actionId as string, + isEphemeral: !isPersistedActionTask(actionTaskExecutorParams), + request, + ...getSourceFromReferences(references), + taskInfo, + executionId, + consumer, + relatedSavedObjects: validatedRelatedSavedObjects(logger, relatedSavedObjects), + actionExecutionId, + }); inMemoryMetrics.increment(IN_MEMORY_METRICS.ACTION_EXECUTIONS); - if ( - executorResult && - executorResult?.status === 'error' && - executorResult?.retry !== undefined && - isRetryableBasedOnAttempts - ) { + if (executorResult.status === 'error') { inMemoryMetrics.increment(IN_MEMORY_METRICS.ACTION_FAILURES); - logger.error( - `Action '${actionId}' failed ${ - !!executorResult.retry ? willRetryMessage : willNotRetryMessage - }: ${executorResult.message}` - ); // Task manager error handler only kicks in when an error thrown (at this time) // So what we have to do is throw when the return status is `error`. throw new ExecutorError( @@ -159,36 +127,10 @@ export class TaskRunnerFactory { executorResult.data, executorResult.retry as boolean | Date ); - } else if (executorResult && executorResult?.status === 'error') { - inMemoryMetrics.increment(IN_MEMORY_METRICS.ACTION_FAILURES); - logger.error( - `Action '${actionId}' failed ${willNotRetryMessage}: ${executorResult.message}` - ); - } - - // Cleanup action_task_params object now that we're done with it - if (isPersistedActionTask(actionTaskExecutorParams)) { - try { - // If the request has reached this far we can assume the user is allowed to run clean up - // We would idealy secure every operation but in order to support clean up of legacy alerts - // we allow this operation in an unsecured manner - // Once support for legacy alert RBAC is dropped, this can be secured - await getUnsecuredSavedObjectsClient(request).delete( - ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, - actionTaskExecutorParams.actionTaskParamsId, - { refresh: false } - ); - } catch (e) { - // Log error only, we shouldn't fail the task because of an error here (if ever there's retry logic) - logger.error( - `Failed to cleanup ${ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE} object [id="${actionTaskExecutorParams.actionTaskParamsId}"]: ${e.message}` - ); - } } }, cancel: async () => { // Write event log entry - const actionTaskExecutorParams = taskInstance.params as ActionTaskExecutorParams; const { spaceId } = actionTaskExecutorParams; const { @@ -221,6 +163,23 @@ export class TaskRunnerFactory { ); return { state: {} }; }, + cleanup: async () => { + // Cleanup action_task_params object now that we're done with it + if (isPersistedActionTask(actionTaskExecutorParams)) { + try { + await savedObjectsRepository.delete( + ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, + actionTaskExecutorParams.actionTaskParamsId, + { refresh: false } + ); + } catch (e) { + // Log error only, we shouldn't fail the task because of an error here (if ever there's retry logic) + logger.error( + `Failed to cleanup ${ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE} object [id="${actionTaskExecutorParams.actionTaskParamsId}"]: ${e.message}` + ); + } + } + }, }; } } diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 76e59fa370fc2..debd5917cf687 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -524,8 +524,9 @@ export class ActionsPlugin implements Plugin spaceIdToNamespace(plugins.spaces, spaceId), - getUnsecuredSavedObjectsClient: (request: KibanaRequest) => - this.getUnsecuredSavedObjectsClient(core.savedObjects, request), + savedObjectsRepository: core.savedObjects.createInternalRepository([ + ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, + ]), }); this.eventLogService!.isEsContextReady().then(() => { diff --git a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts index 0b5036beb612d..998d8a4b95e47 100644 --- a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts +++ b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts @@ -143,6 +143,7 @@ export const updateFieldsAndMarkAsFailed = ({ .join(' ')}`; const setScheduledAtAndMarkAsClaimed = `${setScheduledAtScript} ${markAsClaimingScript}`; + // TODO: Remove section updating status to "failed" and rather let Kibana process the task and it's related cleanup return { source: ` if (params.claimableTaskTypes.contains(ctx._source.task.taskType)) { diff --git a/x-pack/plugins/task_manager/server/task.ts b/x-pack/plugins/task_manager/server/task.ts index ebb957e54699a..7082ca1537d53 100644 --- a/x-pack/plugins/task_manager/server/task.ts +++ b/x-pack/plugins/task_manager/server/task.ts @@ -91,6 +91,7 @@ export type CancelFunction = () => Promise; export interface CancellableTask { run: RunFunction; cancel?: CancelFunction; + cleanup?: () => Promise; } export type TaskRunCreatorFunction = (context: RunContext) => CancellableTask; diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.ts index 95d0105d10685..b2d3c713fc632 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.ts @@ -545,7 +545,16 @@ export class TaskManagerRunner implements TaskRunner { } else if (fieldUpdates.status === TaskStatus.Failed) { // Delete the SO instead so it doesn't remain in the index forever await this.bufferedTaskStore.remove(this.id); - asRan(this.instance.task); + this.instance = asRan(this.instance.task); + if (this.task?.cleanup) { + try { + await this.task.cleanup(); + } catch (e) { + this.logger.error( + `Error encountered when running onTaskRemoved() hook for ${this}: ${e.message}` + ); + } + } } else { this.instance = asRan( await this.bufferedTaskStore.update( @@ -575,6 +584,15 @@ export class TaskManagerRunner implements TaskRunner { try { await this.bufferedTaskStore.remove(this.id); this.instance = asRan(this.instance.task); + if (this.task?.cleanup) { + try { + await this.task.cleanup(); + } catch (e) { + this.logger.error( + `Error encountered when running onTaskRemoved() hook for ${this}: ${e.message}` + ); + } + } } catch (err) { if (err.statusCode === 404) { this.logger.warn(`Task cleanup of ${this} failed in processing. Was remove called twice?`); From 934674a69f36aca4d32274811d7de89a4ab5fec9 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 10 Mar 2023 08:44:33 -0500 Subject: [PATCH 03/17] Add cleanup hook and handle tasks that are timed out and out of attempts --- .../actions/server/action_type_registry.ts | 3 +- .../server/lib/task_runner_factory.test.ts | 157 +++++------------- .../actions/server/lib/task_runner_factory.ts | 39 +++-- .../task_manager/server/polling_lifecycle.ts | 11 +- .../mark_available_tasks_as_claimed.test.ts | 6 +- .../mark_available_tasks_as_claimed.ts | 7 +- .../task_manager/server/task_pool.test.ts | 2 + .../task_running/ephemeral_task_runner.ts | 13 ++ .../server/task_running/task_runner.test.ts | 26 +-- .../server/task_running/task_runner.ts | 54 +++--- 10 files changed, 132 insertions(+), 186 deletions(-) diff --git a/x-pack/plugins/actions/server/action_type_registry.ts b/x-pack/plugins/actions/server/action_type_registry.ts index d274118650b61..09f7fa5370fc0 100644 --- a/x-pack/plugins/actions/server/action_type_registry.ts +++ b/x-pack/plugins/actions/server/action_type_registry.ts @@ -152,8 +152,7 @@ export class ActionTypeRegistry { [`actions:${actionType.id}`]: { title: actionType.name, maxAttempts, - createTaskRunner: (context: RunContext) => - this.taskRunnerFactory.create(context, maxAttempts), + createTaskRunner: (context: RunContext) => this.taskRunnerFactory.create(context), }, }); // No need to notify usage on basic action types diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts index e5873169ceddb..ed2f990ffadc8 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts @@ -12,14 +12,22 @@ import { TaskRunnerFactory } from './task_runner_factory'; import { actionTypeRegistryMock } from '../action_type_registry.mock'; import { actionExecutorMock } from './action_executor.mock'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; -import { savedObjectsClientMock, loggingSystemMock, httpServiceMock } from '@kbn/core/server/mocks'; +import { + savedObjectsClientMock, + loggingSystemMock, + httpServiceMock, + savedObjectsRepositoryMock, +} from '@kbn/core/server/mocks'; import { eventLoggerMock } from '@kbn/event-log-plugin/server/mocks'; import { ActionTypeDisabledError } from './errors'; import { actionsClientMock } from '../mocks'; import { inMemoryMetricsMock } from '../monitoring/in_memory_metrics.mock'; import { IN_MEMORY_METRICS } from '../monitoring'; import { pick } from 'lodash'; -import { isRetryableError } from '@kbn/task-manager-plugin/server/task_running'; +import { + isRetryableError, + isUnrecoverableError, +} from '@kbn/task-manager-plugin/server/task_running'; const executeParamsFields = [ 'actionId', @@ -85,15 +93,12 @@ const taskRunnerFactoryInitializerParams = { logger: loggingSystemMock.create().get(), encryptedSavedObjectsClient: mockedEncryptedSavedObjectsClient, basePathService: httpServiceMock.createBasePath(), - getUnsecuredSavedObjectsClient: jest.fn().mockReturnValue(services.savedObjectsClient), + savedObjectsRepository: savedObjectsRepositoryMock.create(), }; beforeEach(() => { jest.resetAllMocks(); actionExecutorInitializerParams.getServices.mockReturnValue(services); - taskRunnerFactoryInitializerParams.getUnsecuredSavedObjectsClient.mockReturnValue( - services.savedObjectsClient - ); }); test(`throws an error if factory isn't initialized`, () => { @@ -287,36 +292,18 @@ test('executes the task by calling the executor with proper parameters when cons ); }); -test('cleans up action_task_params object', async () => { +test('cleans up action_task_params object through the cleanup runner method', async () => { const taskRunner = taskRunnerFactory.create({ taskInstance: mockedTaskInstance, }); - mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' }); - spaceIdToNamespace.mockReturnValueOnce('namespace-test'); - mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({ - id: '3', - type: 'action_task_params', - attributes: { - actionId: '2', - params: { baz: true }, - executionId: '123abc', - apiKey: Buffer.from('123:abc').toString('base64'), - }, - references: [ - { - id: '2', - name: 'actionRef', - type: 'action', - }, - ], - }); - - await taskRunner.run(); + await taskRunner.cleanup(); - expect(services.savedObjectsClient.delete).toHaveBeenCalledWith('action_task_params', '3', { - refresh: false, - }); + expect(taskRunnerFactoryInitializerParams.savedObjectsRepository.delete).toHaveBeenCalledWith( + 'action_task_params', + '3', + { refresh: false } + ); }); test('task runner should implement CancellableTask cancel method with logging warning message', async () => { @@ -351,37 +338,22 @@ test('task runner should implement CancellableTask cancel method with logging wa ); }); -test('runs successfully when cleanup fails and logs the error', async () => { +test('cleanup runs successfully when action_task_params cleanup fails and logs the error', async () => { const taskRunner = taskRunnerFactory.create({ taskInstance: mockedTaskInstance, }); - mockedActionExecutor.execute.mockResolvedValueOnce({ status: 'ok', actionId: '2' }); - spaceIdToNamespace.mockReturnValueOnce('namespace-test'); - mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({ - id: '3', - type: 'action_task_params', - attributes: { - actionId: '2', - params: { baz: true }, - executionId: '123abc', - apiKey: Buffer.from('123:abc').toString('base64'), - }, - references: [ - { - id: '2', - name: 'actionRef', - type: 'action', - }, - ], - }); - services.savedObjectsClient.delete.mockRejectedValueOnce(new Error('Fail')); + taskRunnerFactoryInitializerParams.savedObjectsRepository.delete.mockRejectedValueOnce( + new Error('Fail') + ); - await taskRunner.run(); + await taskRunner.cleanup(); - expect(services.savedObjectsClient.delete).toHaveBeenCalledWith('action_task_params', '3', { - refresh: false, - }); + expect(taskRunnerFactoryInitializerParams.savedObjectsRepository.delete).toHaveBeenCalledWith( + 'action_task_params', + '3', + { refresh: false } + ); expect(taskRunnerFactoryInitializerParams.logger.error).toHaveBeenCalledWith( 'Failed to cleanup action_task_params object [id="3"]: Fail' ); @@ -691,15 +663,12 @@ test(`doesn't use API key when not provided`, async () => { }); test(`throws an error when license doesn't support the action type`, async () => { - const taskRunner = taskRunnerFactory.create( - { - taskInstance: { - ...mockedTaskInstance, - attempts: 1, - }, + const taskRunner = taskRunnerFactory.create({ + taskInstance: { + ...mockedTaskInstance, + attempts: 1, }, - 2 - ); + }); mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({ id: '3', @@ -726,7 +695,7 @@ test(`throws an error when license doesn't support the action type`, async () => await taskRunner.run(); throw new Error('Should have thrown'); } catch (e) { - expect(isRetryableError(e)).toEqual(true); + expect(isUnrecoverableError(e)).toEqual(true); } }); @@ -771,57 +740,9 @@ test(`will throw an error with retry: false if the task is not retryable`, async } expect(err).toBeDefined(); expect(isRetryableError(err)).toEqual(false); - expect(taskRunnerFactoryInitializerParams.logger.error as jest.Mock).toHaveBeenCalledWith( - `Action '2' failed and will not retry: Error message` - ); -}); - -test(`treats errors as successes if the task is not retryable`, async () => { - const taskRunner = taskRunnerFactory.create({ - taskInstance: { - ...mockedTaskInstance, - attempts: 1, - }, - }); - - mockedEncryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValueOnce({ - id: '3', - type: 'action_task_params', - attributes: { - actionId: '2', - params: { baz: true }, - executionId: '123abc', - apiKey: Buffer.from('123:abc').toString('base64'), - }, - references: [ - { - id: '2', - name: 'actionRef', - type: 'action', - }, - ], - }); - mockedActionExecutor.execute.mockResolvedValueOnce({ - status: 'error', - actionId: '2', - message: 'Error message', - data: { foo: true }, - retry: false, - }); - - let err; - try { - await taskRunner.run(); - } catch (e) { - err = e; - } - expect(err).toBeUndefined(); - expect(taskRunnerFactoryInitializerParams.logger.error as jest.Mock).toHaveBeenCalledWith( - `Action '2' failed and will not retry: Error message` - ); }); -test('will throw a retry error if the error is thrown instead of returned', async () => { +test('will rethrow the error if the error is thrown instead of returned', async () => { const taskRunner = taskRunnerFactory.create({ taskInstance: { ...mockedTaskInstance, @@ -846,7 +767,8 @@ test('will throw a retry error if the error is thrown instead of returned', asyn }, ], }); - mockedActionExecutor.execute.mockRejectedValueOnce({}); + const thrownError = new Error('Fail'); + mockedActionExecutor.execute.mockRejectedValueOnce(thrownError); let err; try { @@ -855,10 +777,7 @@ test('will throw a retry error if the error is thrown instead of returned', asyn err = e; } expect(err).toBeDefined(); - expect(isRetryableError(err)).toEqual(true); - expect(taskRunnerFactoryInitializerParams.logger.error as jest.Mock).toHaveBeenCalledWith( - `Action '2' failed and will retry: undefined` - ); + expect(thrownError).toEqual(err); }); test('increments monitoring metrics after execution', async () => { diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index e8082a763eae2..f0fddbdd2f7bc 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -22,7 +22,10 @@ import { } from '@kbn/core/server'; import { RunContext } from '@kbn/task-manager-plugin/server'; import { EncryptedSavedObjectsClient } from '@kbn/encrypted-saved-objects-plugin/server'; -import { throwRetryableError } from '@kbn/task-manager-plugin/server/task_running'; +import { + throwRetryableError, + throwUnrecoverableError, +} from '@kbn/task-manager-plugin/server/task_running'; import { ActionExecutorContract } from './action_executor'; import { ActionTaskParams, @@ -37,6 +40,7 @@ import { asSavedObjectExecutionSource } from './action_execution_source'; import { RelatedSavedObjects, validatedRelatedSavedObjects } from './related_saved_objects'; import { injectSavedObjectReferences } from './action_task_params_utils'; import { InMemoryMetrics, IN_MEMORY_METRICS } from '../monitoring'; +import { ActionTypeDisabledError } from './errors'; export interface TaskRunnerContext { logger: Logger; @@ -104,18 +108,27 @@ export class TaskRunnerFactory { const request = getFakeRequest(apiKey); basePathService.set(request, path); - const executorResult: ActionTypeExecutorResult = await actionExecutor.execute({ - params, - actionId: actionId as string, - isEphemeral: !isPersistedActionTask(actionTaskExecutorParams), - request, - ...getSourceFromReferences(references), - taskInfo, - executionId, - consumer, - relatedSavedObjects: validatedRelatedSavedObjects(logger, relatedSavedObjects), - actionExecutionId, - }); + let executorResult: ActionTypeExecutorResult | undefined; + try { + executorResult = await actionExecutor.execute({ + params, + actionId: actionId as string, + isEphemeral: !isPersistedActionTask(actionTaskExecutorParams), + request, + ...getSourceFromReferences(references), + taskInfo, + executionId, + consumer, + relatedSavedObjects: validatedRelatedSavedObjects(logger, relatedSavedObjects), + actionExecutionId, + }); + } catch (e) { + if (e instanceof ActionTypeDisabledError) { + // We'll stop re-trying due to action being forbidden + throwUnrecoverableError(e); + } + throw e; + } inMemoryMetrics.increment(IN_MEMORY_METRICS.ACTION_EXECUTIONS); if (executorResult.status === 'error') { diff --git a/x-pack/plugins/task_manager/server/polling_lifecycle.ts b/x-pack/plugins/task_manager/server/polling_lifecycle.ts index 65790f83c422e..a0a626027c4d4 100644 --- a/x-pack/plugins/task_manager/server/polling_lifecycle.ts +++ b/x-pack/plugins/task_manager/server/polling_lifecycle.ts @@ -270,7 +270,16 @@ export class TaskPollingLifecycle { this.createTaskRunnerForTask, // place tasks in the Task Pool async (tasks: TaskRunner[]) => { - const result = await this.pool.run(tasks); + const tasksToRun = []; + for (const task of tasks) { + if (task.isAdHocTaskAndOutOfAttempts) { + this.logger.debug(`Removing ${task} because the max attempts have been reached.`); + await task.removeTask(); + } else { + tasksToRun.push(task); + } + } + const result = await this.pool.run(tasksToRun); // Emit the load after fetching tasks, giving us a good metric for evaluating how // busy Task manager tends to be in this Kibana instance this.emitEvent(asTaskManagerStatEvent('load', asOk(this.pool.workerLoad))); diff --git a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts index 28957d7618449..56686ea7d46c1 100644 --- a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts +++ b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.test.ts @@ -138,8 +138,7 @@ if (doc['task.runAt'].size()!=0) { script: { source: ` if (params.claimableTaskTypes.contains(ctx._source.task.taskType)) { - if (ctx._source.task.schedule != null || ctx._source.task.attempts < params.taskMaxAttempts[ctx._source.task.taskType]) { - if(ctx._source.task.retryAt != null && ZonedDateTime.parse(ctx._source.task.retryAt).toInstant().toEpochMilli() < params.now) { + if(ctx._source.task.retryAt != null && ZonedDateTime.parse(ctx._source.task.retryAt).toInstant().toEpochMilli() < params.now) { ctx._source.task.scheduledAt=ctx._source.task.retryAt; } else { ctx._source.task.scheduledAt=ctx._source.task.runAt; @@ -147,9 +146,6 @@ if (doc['task.runAt'].size()!=0) { ctx._source.task.status = "claiming"; ${Object.keys(fieldUpdates) .map((field) => `ctx._source.task.${field}=params.fieldUpdates.${field};`) .join(' ')} - } else { - ctx._source.task.status = "failed"; - } } else if (params.unusedTaskTypes.contains(ctx._source.task.taskType)) { ctx._source.task.status = "unrecognized"; } else { diff --git a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts index 998d8a4b95e47..d2137f6c82b08 100644 --- a/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts +++ b/x-pack/plugins/task_manager/server/queries/mark_available_tasks_as_claimed.ts @@ -143,15 +143,10 @@ export const updateFieldsAndMarkAsFailed = ({ .join(' ')}`; const setScheduledAtAndMarkAsClaimed = `${setScheduledAtScript} ${markAsClaimingScript}`; - // TODO: Remove section updating status to "failed" and rather let Kibana process the task and it's related cleanup return { source: ` if (params.claimableTaskTypes.contains(ctx._source.task.taskType)) { - if (ctx._source.task.schedule != null || ctx._source.task.attempts < params.taskMaxAttempts[ctx._source.task.taskType]) { - ${setScheduledAtAndMarkAsClaimed} - } else { - ctx._source.task.status = "failed"; - } + ${setScheduledAtAndMarkAsClaimed} } else if (params.unusedTaskTypes.contains(ctx._source.task.taskType)) { ctx._source.task.status = "unrecognized"; } else { diff --git a/x-pack/plugins/task_manager/server/task_pool.test.ts b/x-pack/plugins/task_manager/server/task_pool.test.ts index baef1587cd242..10e440184ab2e 100644 --- a/x-pack/plugins/task_manager/server/task_pool.test.ts +++ b/x-pack/plugins/task_manager/server/task_pool.test.ts @@ -409,6 +409,8 @@ describe('TaskPool', () => { run: mockRun(), stage: TaskRunningStage.PENDING, toString: () => `TaskType "shooooo"`, + isAdHocTaskAndOutOfAttempts: false, + removeTask: jest.fn(), get expiration() { return new Date(); }, diff --git a/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts b/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts index baf4e253c67a9..a41297c90f67b 100644 --- a/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/ephemeral_task_runner.ts @@ -181,6 +181,14 @@ export class EphemeralTaskManagerRunner implements TaskRunner { return this.expiration < new Date(); } + /** + * Returns true whenever the task is ad hoc and has ran out of attempts. When true before + * running a task, the task should be deleted instead of ran. + */ + public get isAdHocTaskAndOutOfAttempts() { + return false; + } + public get isEphemeral() { return true; } @@ -252,6 +260,11 @@ export class EphemeralTaskManagerRunner implements TaskRunner { } } + /** + * Used by the non-ephemeral task runner + */ + public async removeTask(): Promise {} + /** * Noop for Ephemeral tasks * diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts index 2598d8084a783..e229b5dc8cedb 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts @@ -896,9 +896,8 @@ describe('TaskManagerRunner', () => { await runner.run(); - const instance = store.update.mock.calls[0][0]; - expect(instance.status).toBe('failed'); - expect(instance.enabled).not.toBeDefined(); + expect(store.remove).toHaveBeenCalled(); + expect(store.update).not.toHaveBeenCalled(); expect(onTaskEvent).toHaveBeenCalledWith( withAnyTiming( @@ -1101,11 +1100,8 @@ describe('TaskManagerRunner', () => { await runner.run(); - expect(store.update).toHaveBeenCalledTimes(1); - const instance = store.update.mock.calls[0][0]; - - expect(instance.status).toBe('failed'); - expect(instance.enabled).not.toBeDefined(); + expect(store.remove).toHaveBeenCalled(); + expect(store.update).not.toHaveBeenCalled(); }); test('bypasses getRetry function (returning false) on error of a recurring task', async () => { @@ -1170,13 +1166,8 @@ describe('TaskManagerRunner', () => { await runner.run(); - expect(store.update).toHaveBeenCalledTimes(1); - const instance = store.update.mock.calls[0][0]; - expect(instance.attempts).toEqual(3); - expect(instance.status).toEqual('failed'); - expect(instance.retryAt!).toBeNull(); - expect(instance.runAt.getTime()).toBeLessThanOrEqual(Date.now()); - expect(instance.enabled).not.toBeDefined(); + expect(store.remove).toHaveBeenCalled(); + expect(store.update).not.toHaveBeenCalled(); }); test(`Doesn't fail recurring tasks when maxAttempts reached`, async () => { @@ -1403,9 +1394,8 @@ describe('TaskManagerRunner', () => { await runner.run(); - const instance = store.update.mock.calls[0][0]; - expect(instance.status).toBe('failed'); - expect(instance.enabled).not.toBeDefined(); + expect(store.remove).toHaveBeenCalled(); + expect(store.update).not.toHaveBeenCalled(); expect(onTaskEvent).toHaveBeenCalledWith( withAnyTiming( diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.ts index 1e787ecf36ef6..858d89f46d70a 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.ts @@ -73,6 +73,8 @@ export interface TaskRunner { isEphemeral?: boolean; toString: () => string; isSameTask: (executionId: string) => boolean; + isAdHocTaskAndOutOfAttempts: boolean; + removeTask: () => Promise; } export enum TaskRunningStage { @@ -258,6 +260,14 @@ export class TaskManagerRunner implements TaskRunner { return this.expiration < new Date(); } + /** + * Returns true whenever the task is ad hoc and has ran out of attempts. When true before + * running a task, the task should be deleted instead of ran. + */ + public get isAdHocTaskAndOutOfAttempts() { + return !this.instance.task.schedule && this.instance.task.attempts >= this.getMaxAttempts(); + } + /** * Returns a log-friendly representation of this task. */ @@ -330,6 +340,19 @@ export class TaskManagerRunner implements TaskRunner { } } + public async removeTask(): Promise { + await this.bufferedTaskStore.remove(this.id); + if (this.task?.cleanup) { + try { + await this.task.cleanup(); + } catch (e) { + this.logger.error( + `Error encountered when running onTaskRemoved() hook for ${this}: ${e.message}` + ); + } + } + } + /** * Attempts to claim exclusive rights to run the task. If the attempt fails * with a 409 (http conflict), we assume another Kibana instance beat us to the punch. @@ -474,8 +497,7 @@ export class TaskManagerRunner implements TaskRunner { return false; } - const maxAttempts = this.definition.maxAttempts || this.defaultMaxAttempts; - return this.instance.task.attempts < maxAttempts; + return this.instance.task.attempts < this.getMaxAttempts(); } private rescheduleFailedRun = ( @@ -544,17 +566,8 @@ export class TaskManagerRunner implements TaskRunner { }); } else if (fieldUpdates.status === TaskStatus.Failed) { // Delete the SO instead so it doesn't remain in the index forever - await this.bufferedTaskStore.remove(this.id); this.instance = asRan(this.instance.task); - if (this.task?.cleanup) { - try { - await this.task.cleanup(); - } catch (e) { - this.logger.error( - `Error encountered when running onTaskRemoved() hook for ${this}: ${e.message}` - ); - } - } + await this.removeTask(); } else { this.instance = asRan( await this.bufferedTaskStore.update( @@ -582,17 +595,8 @@ export class TaskManagerRunner implements TaskRunner { private async processResultWhenDone(): Promise { // not a recurring task: clean up by removing the task instance from store try { - await this.bufferedTaskStore.remove(this.id); this.instance = asRan(this.instance.task); - if (this.task?.cleanup) { - try { - await this.task.cleanup(); - } catch (e) { - this.logger.error( - `Error encountered when running onTaskRemoved() hook for ${this}: ${e.message}` - ); - } - } + await this.removeTask(); } catch (err) { if (err.statusCode === 404) { this.logger.warn(`Task cleanup of ${this} failed in processing. Was remove called twice?`); @@ -682,6 +686,12 @@ export class TaskManagerRunner implements TaskRunner { } return result; } + + private getMaxAttempts() { + return this.definition.maxAttempts !== undefined + ? this.definition.maxAttempts + : this.defaultMaxAttempts; + } } function sanitizeInstance(instance: ConcreteTaskInstance): ConcreteTaskInstance { From 2c58dc3aa635011bd73d4d74e4c9828e6d2edf1e Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 10 Mar 2023 11:45:12 -0500 Subject: [PATCH 04/17] Provide namespace to repository when deleting action_task_params --- x-pack/plugins/actions/server/lib/task_runner_factory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index bb9a826271969..deb58fc5360cf 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -192,7 +192,7 @@ export class TaskRunnerFactory { await savedObjectsRepository.delete( ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, actionTaskExecutorParams.actionTaskParamsId, - { refresh: false } + { refresh: false, namespace: spaceIdToNamespace(actionTaskExecutorParams.spaceId) } ); } catch (e) { // Log error only, we shouldn't fail the task because of an error here (if ever there's retry logic) From b530399d59450a8ed7529062e9fe705983346b20 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 20 Mar 2023 12:56:51 -0400 Subject: [PATCH 05/17] Fix failing tests and cleanup bulkRemoveIfExists --- .../common/try_to_remove_tasks.ts | 8 ++-- .../rules_client/tests/bulk_delete.test.ts | 20 ++++----- .../rules_client/tests/bulk_disable.test.ts | 14 +++--- .../alerting/server/rules_client/tests/lib.ts | 2 +- .../server/lib/bulk_remove_if_exist.test.ts | 43 ------------------- .../server/lib/bulk_remove_if_exist.ts | 26 ----------- x-pack/plugins/task_manager/server/mocks.ts | 2 +- x-pack/plugins/task_manager/server/plugin.ts | 8 +--- 8 files changed, 25 insertions(+), 98 deletions(-) delete mode 100644 x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.test.ts delete mode 100644 x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.ts diff --git a/x-pack/plugins/alerting/server/rules_client/common/try_to_remove_tasks.ts b/x-pack/plugins/alerting/server/rules_client/common/try_to_remove_tasks.ts index 89ad52d232332..962f68bf5d959 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/try_to_remove_tasks.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/try_to_remove_tasks.ts @@ -20,12 +20,12 @@ export const tryToRemoveTasks = async ({ }) => { const taskIdsFailedToBeDeleted: string[] = []; const taskIdsSuccessfullyDeleted: string[] = []; - return await withSpan({ name: 'taskManager.bulkRemoveIfExist', type: 'rules' }, async () => { + return await withSpan({ name: 'taskManager.bulkRemove', type: 'rules' }, async () => { if (taskIdsToDelete.length > 0) { try { - const resultFromDeletingTasks = await taskManager.bulkRemoveIfExist(taskIdsToDelete); + const resultFromDeletingTasks = await taskManager.bulkRemove(taskIdsToDelete); resultFromDeletingTasks?.statuses.forEach((status) => { - if (status.success) { + if (status.success || status.error?.statusCode === 404) { taskIdsSuccessfullyDeleted.push(status.id); } else { taskIdsFailedToBeDeleted.push(status.id); @@ -49,7 +49,7 @@ export const tryToRemoveTasks = async ({ logger.error( `Failure to delete schedules for underlying tasks: ${taskIdsToDelete.join( ', ' - )}. TaskManager bulkRemoveIfExist failed with Error: ${error.message}` + )}. TaskManager bulkRemove failed with Error: ${error.message}` ); } } diff --git a/x-pack/plugins/alerting/server/rules_client/tests/bulk_delete.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/bulk_delete.test.ts index 92621434dc7b9..b61ef395d4e72 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/bulk_delete.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/bulk_delete.test.ts @@ -141,8 +141,8 @@ describe('bulkDelete', () => { enabledRule1, enabledRule2, ]); - expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledTimes(1); - expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledWith(['id1']); + expect(taskManager.bulkRemove).toHaveBeenCalledTimes(1); + expect(taskManager.bulkRemove).toHaveBeenCalledWith(['id1']); expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledTimes(1); expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledWith( { apiKeys: ['MTIzOmFiYw=='] }, @@ -205,8 +205,8 @@ describe('bulkDelete', () => { const result = await rulesClient.bulkDeleteRules({ ids: ['id1', 'id2'] }); expect(unsecuredSavedObjectsClient.bulkDelete).toHaveBeenCalledTimes(4); - expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledTimes(1); - expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledWith(['id1']); + expect(taskManager.bulkRemove).toHaveBeenCalledTimes(1); + expect(taskManager.bulkRemove).toHaveBeenCalledWith(['id1']); expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledTimes(1); expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledWith( { apiKeys: ['MTIzOmFiYw=='] }, @@ -263,8 +263,8 @@ describe('bulkDelete', () => { const result = await rulesClient.bulkDeleteRules({ ids: ['id1', 'id2'] }); expect(unsecuredSavedObjectsClient.bulkDelete).toHaveBeenCalledTimes(2); - expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledTimes(1); - expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledWith(['id1', 'id2']); + expect(taskManager.bulkRemove).toHaveBeenCalledTimes(1); + expect(taskManager.bulkRemove).toHaveBeenCalledWith(['id1', 'id2']); expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledTimes(1); expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledWith( { apiKeys: ['MTIzOmFiYw==', 'MzIxOmFiYw=='] }, @@ -321,7 +321,7 @@ describe('bulkDelete', () => { { id: 'id2', type: 'alert', success: true }, ], }); - taskManager.bulkRemoveIfExist.mockImplementation(async () => ({ + taskManager.bulkRemove.mockImplementation(async () => ({ statuses: [ { id: 'id1', @@ -349,7 +349,7 @@ describe('bulkDelete', () => { { id: 'id2', type: 'alert', success: true }, ], }); - taskManager.bulkRemoveIfExist.mockImplementation(() => { + taskManager.bulkRemove.mockImplementation(() => { throw new Error('UPS'); }); @@ -357,7 +357,7 @@ describe('bulkDelete', () => { expect(logger.error).toBeCalledTimes(1); expect(logger.error).toBeCalledWith( - 'Failure to delete schedules for underlying tasks: id1, id2. TaskManager bulkRemoveIfExist failed with Error: UPS' + 'Failure to delete schedules for underlying tasks: id1, id2. TaskManager bulkRemove failed with Error: UPS' ); }); @@ -369,7 +369,7 @@ describe('bulkDelete', () => { { id: 'id2', type: 'alert', success: true }, ], }); - taskManager.bulkRemoveIfExist.mockImplementation(async () => ({ + taskManager.bulkRemove.mockImplementation(async () => ({ statuses: [ { id: 'id1', diff --git a/x-pack/plugins/alerting/server/rules_client/tests/bulk_disable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/bulk_disable.test.ts index fb5995f8724aa..e69dd1b0ffb44 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/bulk_disable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/bulk_disable.test.ts @@ -399,7 +399,7 @@ describe('bulkDisableRules', () => { ], }); - taskManager.bulkRemoveIfExist.mockResolvedValue({ + taskManager.bulkRemove.mockResolvedValue({ statuses: [ { id: 'id1', type: 'alert', success: true }, { id: 'id2', type: 'alert', success: false }, @@ -408,8 +408,8 @@ describe('bulkDisableRules', () => { await rulesClient.bulkDisableRules({ filter: 'fake_filter' }); - expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledTimes(1); - expect(taskManager.bulkRemoveIfExist).toHaveBeenCalledWith(['taskId1', 'taskId2']); + expect(taskManager.bulkRemove).toHaveBeenCalledTimes(1); + expect(taskManager.bulkRemove).toHaveBeenCalledWith(['taskId1', 'taskId2']); expect(logger.debug).toBeCalledTimes(1); expect(logger.debug).toBeCalledWith( @@ -477,7 +477,7 @@ describe('bulkDisableRules', () => { ); }); - test('should not throw an error if taskManager.bulkRemoveIfExist throw an error', async () => { + test('should not throw an error if taskManager.bulkRemove throw an error', async () => { unsecuredSavedObjectsClient.bulkCreate.mockResolvedValue({ saved_objects: [ { @@ -490,15 +490,15 @@ describe('bulkDisableRules', () => { ], }); - taskManager.bulkRemoveIfExist.mockImplementation(() => { - throw new Error('Something happend during bulkRemoveIfExist'); + taskManager.bulkRemove.mockImplementation(() => { + throw new Error('Something happend during bulkRemove'); }); await rulesClient.bulkDisableRules({ filter: 'fake_filter' }); expect(logger.error).toBeCalledTimes(1); expect(logger.error).toHaveBeenCalledWith( - 'Failure to delete schedules for underlying tasks: taskId1. TaskManager bulkRemoveIfExist failed with Error: Something happend during bulkRemoveIfExist' + 'Failure to delete schedules for underlying tasks: taskId1. TaskManager bulkRemove failed with Error: Something happend during bulkRemove' ); }); }); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/lib.ts b/x-pack/plugins/alerting/server/rules_client/tests/lib.ts index 6328708f4bae0..f036e2cb02298 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/lib.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/lib.ts @@ -68,7 +68,7 @@ export function getBeforeSetup( ownerId: null, enabled: false, }); - taskManager.bulkRemoveIfExist.mockResolvedValue({ + taskManager.bulkRemove.mockResolvedValue({ statuses: [{ id: 'taskId', type: 'alert', success: true }], }); const actionsClient = actionsClientMock.create(); diff --git a/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.test.ts b/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.test.ts deleted file mode 100644 index 0b1c08f448398..0000000000000 --- a/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { v4 as uuidv4 } from 'uuid'; -import { SavedObjectsErrorHelpers } from '@kbn/core/server'; -import { bulkRemoveIfExist } from './bulk_remove_if_exist'; -import { taskStoreMock } from '../task_store.mock'; - -describe('removeIfExists', () => { - const ids = [uuidv4(), uuidv4()]; - - test('removes the tasks by its IDs', async () => { - const ts = taskStoreMock.create({}); - - expect(await bulkRemoveIfExist(ts, ids)).toBe(undefined); - expect(ts.bulkRemove).toHaveBeenCalledWith(ids); - }); - - test('handles 404 errors caused by the task not existing', async () => { - const ts = taskStoreMock.create({}); - - ts.bulkRemove.mockRejectedValue( - SavedObjectsErrorHelpers.createGenericNotFoundError('task', ids[0]) - ); - - expect(await bulkRemoveIfExist(ts, ids)).toBe(undefined); - expect(ts.bulkRemove).toHaveBeenCalledWith(ids); - }); - - test('throws if any other error is caused by task removal', async () => { - const ts = taskStoreMock.create({}); - - const error = SavedObjectsErrorHelpers.createInvalidVersionError(uuidv4()); - ts.bulkRemove.mockRejectedValue(error); - - expect(bulkRemoveIfExist(ts, ids)).rejects.toBe(error); - expect(ts.bulkRemove).toHaveBeenCalledWith(ids); - }); -}); diff --git a/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.ts b/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.ts deleted file mode 100644 index c3c1a61868e60..0000000000000 --- a/x-pack/plugins/task_manager/server/lib/bulk_remove_if_exist.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SavedObjectsErrorHelpers } from '@kbn/core/server'; -import { TaskStore } from '../task_store'; - -/** - * Removes a task from the store, ignoring a not found error - * Other errors are re-thrown - * - * @param taskStore - * @param taskIds - */ -export async function bulkRemoveIfExist(taskStore: TaskStore, taskIds: string[]) { - try { - return await taskStore.bulkRemove(taskIds); - } catch (err) { - if (!SavedObjectsErrorHelpers.isNotFoundError(err)) { - throw err; - } - } -} diff --git a/x-pack/plugins/task_manager/server/mocks.ts b/x-pack/plugins/task_manager/server/mocks.ts index 551efc9c8c52b..1363b0ab9b1ee 100644 --- a/x-pack/plugins/task_manager/server/mocks.ts +++ b/x-pack/plugins/task_manager/server/mocks.ts @@ -24,12 +24,12 @@ const createStartMock = () => { get: jest.fn(), aggregate: jest.fn(), remove: jest.fn(), + bulkRemove: jest.fn(), schedule: jest.fn(), runSoon: jest.fn(), ephemeralRunNow: jest.fn(), ensureScheduled: jest.fn(), removeIfExists: jest.fn(), - bulkRemoveIfExist: jest.fn(), supportsEphemeralTasks: jest.fn(), bulkUpdateSchedules: jest.fn(), bulkSchedule: jest.fn(), diff --git a/x-pack/plugins/task_manager/server/plugin.ts b/x-pack/plugins/task_manager/server/plugin.ts index 100254f6dae32..1fb28465f5bce 100644 --- a/x-pack/plugins/task_manager/server/plugin.ts +++ b/x-pack/plugins/task_manager/server/plugin.ts @@ -18,12 +18,10 @@ import { ServiceStatusLevels, CoreStatus, } from '@kbn/core/server'; -import type { SavedObjectsBulkDeleteResponse } from '@kbn/core/server'; import { TaskPollingLifecycle } from './polling_lifecycle'; import { TaskManagerConfig } from './config'; import { createInitialMiddleware, addMiddlewareToChain, Middleware } from './lib/middleware'; import { removeIfExists } from './lib/remove_if_exists'; -import { bulkRemoveIfExist } from './lib/bulk_remove_if_exist'; import { setupSavedObjects } from './saved_objects'; import { TaskDefinitionRegistry, TaskTypeDictionary, REMOVED_TYPES } from './task_type_dictionary'; import { AggregationOpts, FetchResult, SearchOpts, TaskStore } from './task_store'; @@ -61,10 +59,8 @@ export type TaskManagerStartContract = Pick< | 'bulkDisable' | 'bulkSchedule' > & - Pick & { + Pick & { removeIfExists: TaskStore['remove']; - } & { - bulkRemoveIfExist: (ids: string[]) => Promise; } & { supportsEphemeralTasks: () => boolean; getRegisteredTypes: () => string[]; @@ -275,7 +271,7 @@ export class TaskManagerPlugin taskStore.aggregate(opts), get: (id: string) => taskStore.get(id), remove: (id: string) => taskStore.remove(id), - bulkRemoveIfExist: (ids: string[]) => bulkRemoveIfExist(taskStore, ids), + bulkRemove: (ids: string[]) => taskStore.bulkRemove(ids), removeIfExists: (id: string) => removeIfExists(taskStore, id), schedule: (...args) => taskScheduling.schedule(...args), bulkSchedule: (...args) => taskScheduling.bulkSchedule(...args), From 05245098a1b1d7af9a5da84ddfd87467eff36508 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 20 Mar 2023 17:17:29 -0400 Subject: [PATCH 06/17] Fix failing test --- .../task_manager/task_management.ts | 48 +++---------------- 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts index 6cc68282ac1da..acf21f68612ad 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts @@ -563,12 +563,12 @@ export default function ({ getService }: FtrProviderContext) { params: { throwOnMarkAsRunning: true }, }); - await delay(DEFAULT_POLL_INTERVAL * 3); + expect(originalTask.attempts).to.eql(0); + // Wait for task manager to attempt running the task a second time await retry.try(async () => { const task = await currentTask(originalTask.id); - expect(task.attempts).to.eql(3); - expect(task.status).to.eql('failed'); + expect(task.attempts).to.eql(2); }); }); @@ -769,17 +769,15 @@ export default function ({ getService }: FtrProviderContext) { }); }); - it('should mark non-recurring task as failed if task is still running but maxAttempts has been reached', async () => { - const task = await scheduleTask({ + it('should flag non-recurring task as failed and delete the task if it is still running but maxAttempts has been reached', async () => { + await scheduleTask({ taskType: 'sampleOneTimeTaskThrowingError', params: {}, }); await retry.try(async () => { - const [scheduledTask] = (await currentTasks()).docs; - expect(scheduledTask.id).to.eql(task.id); - expect(scheduledTask.status).to.eql('failed'); - expect(scheduledTask.attempts).to.eql(3); + const results = (await currentTasks()).docs; + expect(results.length).to.eql(0); }); }); @@ -894,38 +892,6 @@ export default function ({ getService }: FtrProviderContext) { }); }); - it('should allow a failed task to be rerun using runSoon', async () => { - const taskThatFailsBeforeRunNow = await scheduleTask({ - taskType: 'singleAttemptSampleTask', - params: { - waitForParams: true, - }, - }); - // tell the task to fail on its next run - await provideParamsToTasksWaitingForParams(taskThatFailsBeforeRunNow.id, { - failWith: 'error on first run', - }); - - // wait for task to fail - await retry.try(async () => { - const tasks = (await currentTasks()).docs; - expect(getTaskById(tasks, taskThatFailsBeforeRunNow.id).status).to.eql('failed'); - }); - - // run the task again - await runTaskSoon({ - id: taskThatFailsBeforeRunNow.id, - }); - - // runTaskSoon should successfully update the runAt property of the task - await retry.try(async () => { - const tasks = (await currentTasks()).docs; - expect( - Date.parse(getTaskById(tasks, taskThatFailsBeforeRunNow.id).runAt) - ).to.be.greaterThan(Date.parse(taskThatFailsBeforeRunNow.runAt)); - }); - }); - // TODO: Add this back in with https://github.com/elastic/kibana/issues/106139 // it('should return the resulting task state when asked to run an ephemeral task now', async () => { // const ephemeralTask = await runEphemeralTaskNow({ From 9ac4f15bffe2e58ba6591b2a08e3e5ad03901b8b Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Mon, 20 Mar 2023 21:22:34 +0000 Subject: [PATCH 07/17] [CI] Auto-commit changed files from 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' --- .../test_suites/task_manager/task_management.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts index acf21f68612ad..7f34e3a2eaa1f 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts @@ -10,7 +10,6 @@ import { random } from 'lodash'; import expect from '@kbn/expect'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import TaskManagerMapping from '@kbn/task-manager-plugin/server/saved_objects/mappings.json'; -import { DEFAULT_POLL_INTERVAL } from '@kbn/task-manager-plugin/server/config'; import { ConcreteTaskInstance, BulkUpdateTaskResult } from '@kbn/task-manager-plugin/server'; import { FtrProviderContext } from '../../ftr_provider_context'; From 0e19d9ac843acae8d149f3c2f506109ce3e66c35 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 21 Mar 2023 06:54:24 -0400 Subject: [PATCH 08/17] Fix typechecks --- .../test_suites/task_manager/task_management.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts index acf21f68612ad..972f0e2e0ef54 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts @@ -10,7 +10,6 @@ import { random } from 'lodash'; import expect from '@kbn/expect'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import TaskManagerMapping from '@kbn/task-manager-plugin/server/saved_objects/mappings.json'; -import { DEFAULT_POLL_INTERVAL } from '@kbn/task-manager-plugin/server/config'; import { ConcreteTaskInstance, BulkUpdateTaskResult } from '@kbn/task-manager-plugin/server'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -18,8 +17,6 @@ const { task: { properties: taskManagerIndexMapping }, } = TaskManagerMapping; -const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - export interface RawDoc { _id: string; _source: any; From 4e296e9b46acf59c7cc48e0e2c133da46e3223f3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 21 Mar 2023 09:15:41 -0400 Subject: [PATCH 09/17] Added some unit tests --- .../server/task_running/task_runner.test.ts | 107 ++++++++++++++++++ .../task_manager/task_management.ts | 2 +- 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts b/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts index e229b5dc8cedb..5812384c66c8e 100644 --- a/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts +++ b/x-pack/plugins/task_manager/server/task_running/task_runner.test.ts @@ -1499,6 +1499,113 @@ describe('TaskManagerRunner', () => { }); }); + describe('isAdHocTaskAndOutOfAttempts', () => { + it(`should return false if the task doesn't have a schedule`, async () => { + const { runner } = await pendingStageSetup({ + instance: { + id: 'foo', + taskType: 'testbar', + }, + }); + + expect(runner.isAdHocTaskAndOutOfAttempts).toEqual(false); + }); + + it(`should return false if the recurring task still has attempts remaining`, async () => { + const { runner } = await pendingStageSetup({ + instance: { + id: 'foo', + taskType: 'testbar', + attempts: 4, + }, + }); + + expect(runner.isAdHocTaskAndOutOfAttempts).toEqual(false); + }); + + it(`should return true if the recurring task is out of attempts`, async () => { + const { runner } = await pendingStageSetup({ + instance: { + id: 'foo', + taskType: 'testbar', + attempts: 5, + }, + }); + + expect(runner.isAdHocTaskAndOutOfAttempts).toEqual(true); + }); + }); + + describe('removeTask()', () => { + it(`should remove the task saved-object`, async () => { + const { runner, store } = await readyToRunStageSetup({ + instance: { + id: 'foo', + taskType: 'testbar', + }, + }); + + await runner.run(); + await runner.removeTask(); + expect(store.remove).toHaveBeenCalledWith('foo'); + }); + + it(`should call the task cleanup function if defined`, async () => { + const cleanupFn = jest.fn(); + const { runner } = await readyToRunStageSetup({ + instance: { + id: 'foo', + taskType: 'testbar2', + }, + definitions: { + testbar2: { + title: 'Bar!', + createTaskRunner: () => ({ + async run() { + return { state: {} }; + }, + cancel: jest.fn(), + cleanup: cleanupFn, + }), + }, + }, + }); + + // Remove task is called after run() with the this.task object defined + await runner.run(); + expect(cleanupFn).toHaveBeenCalledTimes(1); + }); + + it(`doesn't throw an error if the cleanup function throws an error`, async () => { + const cleanupFn = jest.fn().mockRejectedValue(new Error('Fail')); + const { runner, logger } = await readyToRunStageSetup({ + instance: { + id: 'foo', + taskType: 'testbar2', + }, + definitions: { + testbar2: { + title: 'Bar!', + createTaskRunner: () => ({ + async run() { + return { state: {} }; + }, + cancel: jest.fn(), + cleanup: cleanupFn, + }), + }, + }, + }); + + // Remove task is called after run() with the this.task object defined + await runner.run(); + expect(cleanupFn).toHaveBeenCalledTimes(1); + expect(logger.error).toHaveBeenCalledWith( + `Error encountered when running onTaskRemoved() hook for testbar2 "foo": Fail` + ); + }); + }); + interface TestOpts { instance?: Partial; definitions?: TaskDefinitionRegistry; diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts index 972f0e2e0ef54..987a498d420d2 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management.ts @@ -766,7 +766,7 @@ export default function ({ getService }: FtrProviderContext) { }); }); - it('should flag non-recurring task as failed and delete the task if it is still running but maxAttempts has been reached', async () => { + it('should delete the task if it is still running but maxAttempts has been reached', async () => { await scheduleTask({ taskType: 'sampleOneTimeTaskThrowingError', params: {}, From f4965f4373b004c28becbff3ff2cf15061b1b68f Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 22 Mar 2023 08:17:33 -0400 Subject: [PATCH 10/17] Try different archives for rules and tasks --- .../tests/alerting/group4/run_soon.ts | 6 +- .../alerting/group4/scheduled_task_id.ts | 8 +- .../{ => rules}/data.json | 66 ---------- .../{ => rules}/mappings.json | 116 ------------------ .../rules_scheduled_task_id/tasks/data.json | 65 ++++++++++ .../tasks/mappings.json | 115 +++++++++++++++++ 6 files changed, 189 insertions(+), 187 deletions(-) rename x-pack/test/functional/es_archives/rules_scheduled_task_id/{ => rules}/data.json (58%) rename x-pack/test/functional/es_archives/rules_scheduled_task_id/{ => rules}/mappings.json (78%) create mode 100644 x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json create mode 100644 x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts index ceaba73b2a2ac..3c0d6a41f2187 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts @@ -22,7 +22,8 @@ export default function createRunSoonTests({ getService }: FtrProviderContext) { const objectRemover = new ObjectRemover(supertest); before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id'); + await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); + await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); }); afterEach(async () => { @@ -30,7 +31,8 @@ export default function createRunSoonTests({ getService }: FtrProviderContext) { }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id'); + await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); + await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); }); it('should successfully run rule where scheduled task id is different than rule id', async () => { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts index b7ad0e47947e1..86c3c172f2a5c 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts @@ -25,7 +25,7 @@ export default function createScheduledTaskIdTests({ getService }: FtrProviderCo const esArchiver = getService('esArchiver'); const retry = getService('retry'); - describe('scheduled task id', () => { + describe.only('scheduled task id', () => { const objectRemover = new ObjectRemover(supertest); async function getScheduledTask(id: string): Promise { const scheduledTask = await es.get({ @@ -36,11 +36,13 @@ export default function createScheduledTaskIdTests({ getService }: FtrProviderCo } before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id'); + await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); + await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id'); + await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); + await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); }); it('cannot create rule with same ID as a scheduled task ID used by another rule', async () => { diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/data.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/data.json similarity index 58% rename from x-pack/test/functional/es_archives/rules_scheduled_task_id/data.json rename to x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/data.json index 25032f09eeb51..6cbc4d402f87d 100644 --- a/x-pack/test/functional/es_archives/rules_scheduled_task_id/data.json +++ b/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/data.json @@ -40,39 +40,6 @@ } } -{ - "type": "doc", - "value": { - "id": "task:329798f0-b0b0-11ea-9510-fdf248d5f2a4", - "index": ".kibana_task_manager_1", - "source": { - "migrationVersion": { - "task": "7.16.0" - }, - "task": { - "attempts": 0, - "ownerId": null, - "params": "{\"alertId\":\"74f3e6d7-b7bb-477d-ac28-92ee22728e6e\",\"spaceId\":\"default\"}", - "retryAt": null, - "runAt": "2021-11-05T16:21:52.148Z", - "schedule": { - "interval": "1m" - }, - "scheduledAt": "2021-11-05T15:28:42.055Z", - "scope": [ - "alerting" - ], - "startedAt": null, - "status": "idle", - "taskType": "alerting:example.always-firing" - }, - "references": [], - "type": "task", - "updated_at": "2021-11-05T16:21:37.629Z" - } - } -} - { "type": "doc", "value": { @@ -114,36 +81,3 @@ } } } - -{ - "type": "doc", - "value": { - "id": "task:46be60d4-ae63-48ed-ab6f-f4d9b4defacf", - "index": ".kibana_task_manager_1", - "source": { - "migrationVersion": { - "task": "7.16.0" - }, - "task": { - "attempts": 0, - "ownerId": null, - "params": "{\"alertId\":\"46be60d4-ae63-48ed-ab6f-f4d9b4defacf\",\"spaceId\":\"default\"}", - "retryAt": null, - "runAt": "2021-11-05T16:21:52.148Z", - "schedule": { - "interval": "1m" - }, - "scheduledAt": "2021-11-05T15:28:42.055Z", - "scope": [ - "alerting" - ], - "startedAt": null, - "status": "idle", - "taskType": "sampleTaskRemovedType" - }, - "references": [], - "type": "task", - "updated_at": "2021-11-05T16:21:37.629Z" - } - } -} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/mappings.json similarity index 78% rename from x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json rename to x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/mappings.json index 45adfd491a09b..babc00babc838 100644 --- a/x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json +++ b/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/mappings.json @@ -342,119 +342,3 @@ } } } - -{ - "type": "index", - "value": { - "aliases": { - ".kibana_task_manager": { - } - }, - "index": ".kibana_task_manager_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "originId": "2f4316de49999235636386fe51dc06c1", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "task": "235412e52d09e7165fac8a67a43ad6b4", - "type": "2f4316de49999235636386fe51dc06c1", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0" - } - }, - "dynamic": "strict", - "properties": { - "migrationVersion": { - "dynamic": "true", - "properties": { - "task": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "task": { - "properties": { - "attempts": { - "type": "integer" - }, - "ownerId": { - "type": "keyword" - }, - "params": { - "type": "text" - }, - "retryAt": { - "type": "date" - }, - "runAt": { - "type": "date" - }, - "schedule": { - "properties": { - "interval": { - "type": "keyword" - } - } - }, - "scheduledAt": { - "type": "date" - }, - "scope": { - "type": "keyword" - }, - "startedAt": { - "type": "date" - }, - "state": { - "type": "text" - }, - "status": { - "type": "keyword" - }, - "taskType": { - "type": "keyword" - }, - "user": { - "type": "keyword" - } - } - }, - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json new file mode 100644 index 0000000000000..c71e4d14cf72d --- /dev/null +++ b/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json @@ -0,0 +1,65 @@ +{ + "type": "doc", + "value": { + "id": "task:329798f0-b0b0-11ea-9510-fdf248d5f2a4", + "index": ".kibana_task_manager_1", + "source": { + "migrationVersion": { + "task": "7.16.0" + }, + "task": { + "attempts": 0, + "ownerId": null, + "params": "{\"alertId\":\"74f3e6d7-b7bb-477d-ac28-92ee22728e6e\",\"spaceId\":\"default\"}", + "retryAt": null, + "runAt": "2021-11-05T16:21:52.148Z", + "schedule": { + "interval": "1m" + }, + "scheduledAt": "2021-11-05T15:28:42.055Z", + "scope": [ + "alerting" + ], + "startedAt": null, + "status": "idle", + "taskType": "alerting:example.always-firing" + }, + "references": [], + "type": "task", + "updated_at": "2021-11-05T16:21:37.629Z" + } + } +} + +{ + "type": "doc", + "value": { + "id": "task:46be60d4-ae63-48ed-ab6f-f4d9b4defacf", + "index": ".kibana_task_manager_1", + "source": { + "migrationVersion": { + "task": "7.16.0" + }, + "task": { + "attempts": 0, + "ownerId": null, + "params": "{\"alertId\":\"46be60d4-ae63-48ed-ab6f-f4d9b4defacf\",\"spaceId\":\"default\"}", + "retryAt": null, + "runAt": "2021-11-05T16:21:52.148Z", + "schedule": { + "interval": "1m" + }, + "scheduledAt": "2021-11-05T15:28:42.055Z", + "scope": [ + "alerting" + ], + "startedAt": null, + "status": "idle", + "taskType": "sampleTaskRemovedType" + }, + "references": [], + "type": "task", + "updated_at": "2021-11-05T16:21:37.629Z" + } + } +} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json new file mode 100644 index 0000000000000..265d017bd72dc --- /dev/null +++ b/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json @@ -0,0 +1,115 @@ +{ + "type": "index", + "value": { + "aliases": { + ".kibana_task_manager": { + } + }, + "index": ".kibana_task_manager_1", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "namespace": "2f4316de49999235636386fe51dc06c1", + "namespaces": "2f4316de49999235636386fe51dc06c1", + "originId": "2f4316de49999235636386fe51dc06c1", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "task": "235412e52d09e7165fac8a67a43ad6b4", + "type": "2f4316de49999235636386fe51dc06c1", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0" + } + }, + "dynamic": "strict", + "properties": { + "migrationVersion": { + "dynamic": "true", + "properties": { + "task": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "task": { + "properties": { + "attempts": { + "type": "integer" + }, + "ownerId": { + "type": "keyword" + }, + "params": { + "type": "text" + }, + "retryAt": { + "type": "date" + }, + "runAt": { + "type": "date" + }, + "schedule": { + "properties": { + "interval": { + "type": "keyword" + } + } + }, + "scheduledAt": { + "type": "date" + }, + "scope": { + "type": "keyword" + }, + "startedAt": { + "type": "date" + }, + "state": { + "type": "text" + }, + "status": { + "type": "keyword" + }, + "taskType": { + "type": "keyword" + }, + "user": { + "type": "keyword" + } + } + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} From 80b8e4f0daef60afeaecdebc839a2ab281aba699 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 22 Mar 2023 08:18:07 -0400 Subject: [PATCH 11/17] Remove exclusive test --- .../spaces_only/tests/alerting/group4/scheduled_task_id.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts index 86c3c172f2a5c..1cedd3871d03e 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts @@ -25,7 +25,7 @@ export default function createScheduledTaskIdTests({ getService }: FtrProviderCo const esArchiver = getService('esArchiver'); const retry = getService('retry'); - describe.only('scheduled task id', () => { + describe('scheduled task id', () => { const objectRemover = new ObjectRemover(supertest); async function getScheduledTask(id: string): Promise { const scheduledTask = await es.get({ From b0b3d68d5f8dfcbc9884407d47e17d2622a4b4db Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 23 Mar 2023 07:03:52 -0400 Subject: [PATCH 12/17] Use two different data archives --- .../tests/alerting/group4/run_soon.ts | 8 +- .../alerting/group4/scheduled_task_id.ts | 6 +- .../es_archives/rules_run_soon/data.json | 74 +++ .../rules => rules_run_soon}/mappings.json | 116 +++++ .../{rules => }/data.json | 66 +++ .../rules_scheduled_task_id/mappings.json | 460 ++++++++++++++++++ .../rules_scheduled_task_id/tasks/data.json | 65 --- .../tasks/mappings.json | 115 ----- 8 files changed, 721 insertions(+), 189 deletions(-) create mode 100644 x-pack/test/functional/es_archives/rules_run_soon/data.json rename x-pack/test/functional/es_archives/{rules_scheduled_task_id/rules => rules_run_soon}/mappings.json (78%) rename x-pack/test/functional/es_archives/rules_scheduled_task_id/{rules => }/data.json (58%) create mode 100644 x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json delete mode 100644 x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json delete mode 100644 x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts index 3c0d6a41f2187..dc68f5f121fbd 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -const LOADED_RULE_ID = '74f3e6d7-b7bb-477d-ac28-92ee22728e6e'; +const LOADED_RULE_ID = 'c6b2c560-0685-42f6-b488-472594cfe915'; // eslint-disable-next-line import/no-default-export export default function createRunSoonTests({ getService }: FtrProviderContext) { @@ -22,8 +22,7 @@ export default function createRunSoonTests({ getService }: FtrProviderContext) { const objectRemover = new ObjectRemover(supertest); before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); - await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); + await esArchiver.load('x-pack/test/functional/es_archives/rules_run_soon'); }); afterEach(async () => { @@ -31,8 +30,7 @@ export default function createRunSoonTests({ getService }: FtrProviderContext) { }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); - await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); + await esArchiver.unload('x-pack/test/functional/es_archives/rules_run_soon'); }); it('should successfully run rule where scheduled task id is different than rule id', async () => { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts index 1cedd3871d03e..b7ad0e47947e1 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts @@ -36,13 +36,11 @@ export default function createScheduledTaskIdTests({ getService }: FtrProviderCo } before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); - await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); + await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); - await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); + await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id'); }); it('cannot create rule with same ID as a scheduled task ID used by another rule', async () => { diff --git a/x-pack/test/functional/es_archives/rules_run_soon/data.json b/x-pack/test/functional/es_archives/rules_run_soon/data.json new file mode 100644 index 0000000000000..8a9041ee938ac --- /dev/null +++ b/x-pack/test/functional/es_archives/rules_run_soon/data.json @@ -0,0 +1,74 @@ +{ + "type": "doc", + "value": { + "id": "alert:c6b2c560-0685-42f6-b488-472594cfe915", + "index": ".kibana_1", + "source": { + "alert": { + "actions": [ + ], + "alertTypeId": "example.always-firing", + "apiKey": "QIUT8u0/kbOakEHSj50jDpVR90MrqOxanEscboYOoa8PxQvcA5jfHash+fqH3b+KNjJ1LpnBcisGuPkufY9j1e32gKzwGZV5Bfys87imHvygJvIM8uKiFF8bQ8Y4NTaxOJO9fAmZPrFy07ZcQMCAQz+DUTgBFqs=", + "apiKeyOwner": "elastic", + "consumer": "alerts", + "createdAt": "2020-06-17T15:35:38.497Z", + "createdBy": "elastic", + "enabled": true, + "muteAll": false, + "mutedInstanceIds": [ + ], + "name": "always-firing-alert", + "params": { + }, + "schedule": { + "interval": "1m" + }, + "scheduledTaskId": "329798f0-b0b0-11ea-9510-fdf248d5f2a4", + "tags": [ + ], + "throttle": null, + "updatedBy": "elastic" + }, + "migrationVersion": { + "alert": "7.16.0" + }, + "references": [ + ], + "type": "alert", + "updated_at": "2020-06-17T15:35:39.839Z" + } + } +} + +{ + "type": "doc", + "value": { + "id": "task:329798f0-b0b0-11ea-9510-fdf248d5f2a4", + "index": ".kibana_task_manager_1", + "source": { + "migrationVersion": { + "task": "7.16.0" + }, + "task": { + "attempts": 0, + "ownerId": null, + "params": "{\"alertId\":\"c6b2c560-0685-42f6-b488-472594cfe915\",\"spaceId\":\"default\"}", + "retryAt": null, + "runAt": "2021-11-05T16:21:52.148Z", + "schedule": { + "interval": "1m" + }, + "scheduledAt": "2021-11-05T15:28:42.055Z", + "scope": [ + "alerting" + ], + "startedAt": null, + "status": "idle", + "taskType": "alerting:example.always-firing" + }, + "references": [], + "type": "task", + "updated_at": "2021-11-05T16:21:37.629Z" + } + } +} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/mappings.json b/x-pack/test/functional/es_archives/rules_run_soon/mappings.json similarity index 78% rename from x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/mappings.json rename to x-pack/test/functional/es_archives/rules_run_soon/mappings.json index babc00babc838..45adfd491a09b 100644 --- a/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/mappings.json +++ b/x-pack/test/functional/es_archives/rules_run_soon/mappings.json @@ -342,3 +342,119 @@ } } } + +{ + "type": "index", + "value": { + "aliases": { + ".kibana_task_manager": { + } + }, + "index": ".kibana_task_manager_1", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "namespace": "2f4316de49999235636386fe51dc06c1", + "namespaces": "2f4316de49999235636386fe51dc06c1", + "originId": "2f4316de49999235636386fe51dc06c1", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "task": "235412e52d09e7165fac8a67a43ad6b4", + "type": "2f4316de49999235636386fe51dc06c1", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0" + } + }, + "dynamic": "strict", + "properties": { + "migrationVersion": { + "dynamic": "true", + "properties": { + "task": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "task": { + "properties": { + "attempts": { + "type": "integer" + }, + "ownerId": { + "type": "keyword" + }, + "params": { + "type": "text" + }, + "retryAt": { + "type": "date" + }, + "runAt": { + "type": "date" + }, + "schedule": { + "properties": { + "interval": { + "type": "keyword" + } + } + }, + "scheduledAt": { + "type": "date" + }, + "scope": { + "type": "keyword" + }, + "startedAt": { + "type": "date" + }, + "state": { + "type": "text" + }, + "status": { + "type": "keyword" + }, + "taskType": { + "type": "keyword" + }, + "user": { + "type": "keyword" + } + } + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/data.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/data.json similarity index 58% rename from x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/data.json rename to x-pack/test/functional/es_archives/rules_scheduled_task_id/data.json index 6cbc4d402f87d..25032f09eeb51 100644 --- a/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/data.json +++ b/x-pack/test/functional/es_archives/rules_scheduled_task_id/data.json @@ -40,6 +40,39 @@ } } +{ + "type": "doc", + "value": { + "id": "task:329798f0-b0b0-11ea-9510-fdf248d5f2a4", + "index": ".kibana_task_manager_1", + "source": { + "migrationVersion": { + "task": "7.16.0" + }, + "task": { + "attempts": 0, + "ownerId": null, + "params": "{\"alertId\":\"74f3e6d7-b7bb-477d-ac28-92ee22728e6e\",\"spaceId\":\"default\"}", + "retryAt": null, + "runAt": "2021-11-05T16:21:52.148Z", + "schedule": { + "interval": "1m" + }, + "scheduledAt": "2021-11-05T15:28:42.055Z", + "scope": [ + "alerting" + ], + "startedAt": null, + "status": "idle", + "taskType": "alerting:example.always-firing" + }, + "references": [], + "type": "task", + "updated_at": "2021-11-05T16:21:37.629Z" + } + } +} + { "type": "doc", "value": { @@ -81,3 +114,36 @@ } } } + +{ + "type": "doc", + "value": { + "id": "task:46be60d4-ae63-48ed-ab6f-f4d9b4defacf", + "index": ".kibana_task_manager_1", + "source": { + "migrationVersion": { + "task": "7.16.0" + }, + "task": { + "attempts": 0, + "ownerId": null, + "params": "{\"alertId\":\"46be60d4-ae63-48ed-ab6f-f4d9b4defacf\",\"spaceId\":\"default\"}", + "retryAt": null, + "runAt": "2021-11-05T16:21:52.148Z", + "schedule": { + "interval": "1m" + }, + "scheduledAt": "2021-11-05T15:28:42.055Z", + "scope": [ + "alerting" + ], + "startedAt": null, + "status": "idle", + "taskType": "sampleTaskRemovedType" + }, + "references": [], + "type": "task", + "updated_at": "2021-11-05T16:21:37.629Z" + } + } +} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json new file mode 100644 index 0000000000000..45adfd491a09b --- /dev/null +++ b/x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json @@ -0,0 +1,460 @@ +{ + "type": "index", + "value": { + "aliases": { + ".kibana": { + } + }, + "index": ".kibana_1", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "action": "6e96ac5e648f57523879661ea72525b7", + "action_task_params": "a9d49f184ee89641044be0ca2950fa3a", + "alert": "7b44fba6773e37c806ce290ea9b7024e", + "apm-indices": "9bb9b2bf1fa636ed8619cbab5ce6a1dd", + "apm-telemetry": "3525d7c22c42bc80f5e6e9cb3f2b26a2", + "application_usage_totals": "c897e4310c5f24b07caaff3db53ae2c1", + "application_usage_transactional": "965839e75f809fefe04f92dc4d99722a", + "canvas-element": "7390014e1091044523666d97247392fc", + "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", + "cases": "32aa96a6d3855ddda53010ae2048ac22", + "cases-comments": "c2061fb929f585df57425102fa928b4b", + "cases-configure": "42711cbb311976c0687853f4c1354572", + "cases-user-actions": "32277330ec6b721abe3b846cfd939a71", + "config": "ae24d22d5986d04124cc6568f771066f", + "dashboard": "d00f614b29a80360e1190193fd333bab", + "file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e", + "graph-workspace": "cd7ba1330e6682e9cc00b78850874be1", + "index-pattern": "66eccb05066c5a89924f48a9e9736499", + "infrastructure-ui-source": "ddc0ecb18383f6b26101a2fadb2dab0c", + "inventory-view": "88fc7e12fd1b45b6f0787323ce4f18d2", + "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", + "lens": "d33c68a69ff1e78c9888dedd2164ac22", + "lens-ui-telemetry": "509bfa5978586998e05f9e303c07a327", + "map": "23d7aa4a720d4938ccde3983f87bd58d", + "maps-telemetry": "bfd39d88aadadb4be597ea984d433dbe", + "metrics-explorer-view": "428e319af3e822c80a84cf87123ca35c", + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9", + "namespace": "2f4316de49999235636386fe51dc06c1", + "namespaces": "2f4316de49999235636386fe51dc06c1", + "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", + "search": "181661168bbadd1eff5902361e2a0d5c", + "space": "c5ca8acafa0beaa4d08d014a97b6bc6b", + "telemetry": "36a616f7026dfa617d6655df850fe16d", + "todo": "082a2cc96a590268344d5cd74c159ac4", + "tsvb-validation-telemetry": "3a37ef6c8700ae6fc97d5c7da00e9215", + "type": "2f4316de49999235636386fe51dc06c1", + "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0", + "upgrade-assistant-reindex-operation": "296a89039fc4260292be36b1b005d8f2", + "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", + "uptime-dynamic-settings": "fcdb453a30092f022f2642db29523d80", + "url": "b675c3be8d76ecf029294d51dc7ec65d", + "visualization": "52d7a13ad68a150c4525b292d23e12cc" + } + }, + "dynamic": "strict", + "properties": { + "action": { + "properties": { + "actionTypeId": { + "type": "keyword" + }, + "config": { + "enabled": false, + "type": "object" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "secrets": { + "type": "binary" + } + } + }, + "action_task_params": { + "properties": { + "actionId": { + "type": "keyword" + }, + "apiKey": { + "type": "binary" + }, + "params": { + "enabled": false, + "type": "object" + } + } + }, + "alert": { + "properties": { + "actions": { + "properties": { + "actionRef": { + "type": "keyword" + }, + "actionTypeId": { + "type": "keyword" + }, + "group": { + "type": "keyword" + }, + "params": { + "enabled": false, + "type": "object" + } + }, + "type": "nested" + }, + "alertTypeId": { + "type": "keyword" + }, + "apiKey": { + "type": "binary" + }, + "apiKeyOwner": { + "type": "keyword" + }, + "consumer": { + "type": "keyword" + }, + "createdAt": { + "type": "date" + }, + "createdBy": { + "type": "keyword" + }, + "enabled": { + "type": "boolean" + }, + "muteAll": { + "type": "boolean" + }, + "mutedInstanceIds": { + "type": "keyword" + }, + "name": { + "fields": { + "keyword": { + "type": "keyword" + } + }, + "type": "text" + }, + "params": { + "enabled": false, + "type": "object" + }, + "schedule": { + "properties": { + "interval": { + "type": "keyword" + } + } + }, + "scheduledTaskId": { + "type": "keyword" + }, + "tags": { + "type": "keyword" + }, + "throttle": { + "type": "keyword" + }, + "updatedBy": { + "type": "keyword" + } + } + }, + "config": { + "dynamic": "true", + "properties": { + "buildNum": { + "type": "keyword" + } + } + }, + "migrationVersion": { + "dynamic": "true", + "properties": { + "alert": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "config": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + }, + "space": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "namespace": { + "type": "keyword" + }, + "namespaces": { + "type": "keyword" + }, + "query": { + "properties": { + "description": { + "type": "text" + }, + "filters": { + "enabled": false, + "type": "object" + }, + "query": { + "properties": { + "language": { + "type": "keyword" + }, + "query": { + "index": false, + "type": "keyword" + } + } + }, + "timefilter": { + "enabled": false, + "type": "object" + }, + "title": { + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "search": { + "properties": { + "columns": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "hits": { + "type": "integer" + }, + "kibanaSavedObjectMeta": { + "properties": { + "searchSourceJSON": { + "type": "text" + } + } + }, + "sort": { + "type": "keyword" + }, + "title": { + "type": "text" + }, + "version": { + "type": "integer" + } + } + }, + "space": { + "properties": { + "_reserved": { + "type": "boolean" + }, + "color": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "disabledFeatures": { + "type": "keyword" + }, + "imageUrl": { + "index": false, + "type": "text" + }, + "initials": { + "type": "keyword" + }, + "name": { + "fields": { + "keyword": { + "ignore_above": 2048, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "1", + "number_of_shards": "1" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + ".kibana_task_manager": { + } + }, + "index": ".kibana_task_manager_1", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "namespace": "2f4316de49999235636386fe51dc06c1", + "namespaces": "2f4316de49999235636386fe51dc06c1", + "originId": "2f4316de49999235636386fe51dc06c1", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "task": "235412e52d09e7165fac8a67a43ad6b4", + "type": "2f4316de49999235636386fe51dc06c1", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0" + } + }, + "dynamic": "strict", + "properties": { + "migrationVersion": { + "dynamic": "true", + "properties": { + "task": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "task": { + "properties": { + "attempts": { + "type": "integer" + }, + "ownerId": { + "type": "keyword" + }, + "params": { + "type": "text" + }, + "retryAt": { + "type": "date" + }, + "runAt": { + "type": "date" + }, + "schedule": { + "properties": { + "interval": { + "type": "keyword" + } + } + }, + "scheduledAt": { + "type": "date" + }, + "scope": { + "type": "keyword" + }, + "startedAt": { + "type": "date" + }, + "state": { + "type": "text" + }, + "status": { + "type": "keyword" + }, + "taskType": { + "type": "keyword" + }, + "user": { + "type": "keyword" + } + } + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json deleted file mode 100644 index c71e4d14cf72d..0000000000000 --- a/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "type": "doc", - "value": { - "id": "task:329798f0-b0b0-11ea-9510-fdf248d5f2a4", - "index": ".kibana_task_manager_1", - "source": { - "migrationVersion": { - "task": "7.16.0" - }, - "task": { - "attempts": 0, - "ownerId": null, - "params": "{\"alertId\":\"74f3e6d7-b7bb-477d-ac28-92ee22728e6e\",\"spaceId\":\"default\"}", - "retryAt": null, - "runAt": "2021-11-05T16:21:52.148Z", - "schedule": { - "interval": "1m" - }, - "scheduledAt": "2021-11-05T15:28:42.055Z", - "scope": [ - "alerting" - ], - "startedAt": null, - "status": "idle", - "taskType": "alerting:example.always-firing" - }, - "references": [], - "type": "task", - "updated_at": "2021-11-05T16:21:37.629Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "task:46be60d4-ae63-48ed-ab6f-f4d9b4defacf", - "index": ".kibana_task_manager_1", - "source": { - "migrationVersion": { - "task": "7.16.0" - }, - "task": { - "attempts": 0, - "ownerId": null, - "params": "{\"alertId\":\"46be60d4-ae63-48ed-ab6f-f4d9b4defacf\",\"spaceId\":\"default\"}", - "retryAt": null, - "runAt": "2021-11-05T16:21:52.148Z", - "schedule": { - "interval": "1m" - }, - "scheduledAt": "2021-11-05T15:28:42.055Z", - "scope": [ - "alerting" - ], - "startedAt": null, - "status": "idle", - "taskType": "sampleTaskRemovedType" - }, - "references": [], - "type": "task", - "updated_at": "2021-11-05T16:21:37.629Z" - } - } -} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json deleted file mode 100644 index 265d017bd72dc..0000000000000 --- a/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "type": "index", - "value": { - "aliases": { - ".kibana_task_manager": { - } - }, - "index": ".kibana_task_manager_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "originId": "2f4316de49999235636386fe51dc06c1", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "task": "235412e52d09e7165fac8a67a43ad6b4", - "type": "2f4316de49999235636386fe51dc06c1", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0" - } - }, - "dynamic": "strict", - "properties": { - "migrationVersion": { - "dynamic": "true", - "properties": { - "task": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "task": { - "properties": { - "attempts": { - "type": "integer" - }, - "ownerId": { - "type": "keyword" - }, - "params": { - "type": "text" - }, - "retryAt": { - "type": "date" - }, - "runAt": { - "type": "date" - }, - "schedule": { - "properties": { - "interval": { - "type": "keyword" - } - } - }, - "scheduledAt": { - "type": "date" - }, - "scope": { - "type": "keyword" - }, - "startedAt": { - "type": "date" - }, - "state": { - "type": "text" - }, - "status": { - "type": "keyword" - }, - "taskType": { - "type": "keyword" - }, - "user": { - "type": "keyword" - } - } - }, - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} From 704892e2f0a5e17316b154b80a622b70c498944c Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 23 Mar 2023 07:11:11 -0400 Subject: [PATCH 13/17] Keep logged errors --- x-pack/plugins/actions/server/lib/task_runner_factory.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index deb58fc5360cf..3b8f4e6853a99 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -133,6 +133,7 @@ export class TaskRunnerFactory { ...getSource(references, source), }); } catch (e) { + logger.error(`Action '${actionId}' failed: ${e.message}`); if (e instanceof ActionTypeDisabledError) { // We'll stop re-trying due to action being forbidden throwUnrecoverableError(e); @@ -143,6 +144,7 @@ export class TaskRunnerFactory { inMemoryMetrics.increment(IN_MEMORY_METRICS.ACTION_EXECUTIONS); if (executorResult.status === 'error') { inMemoryMetrics.increment(IN_MEMORY_METRICS.ACTION_FAILURES); + logger.error(`Action '${actionId}' failed: ${executorResult.message}`); // Task manager error handler only kicks in when an error thrown (at this time) // So what we have to do is throw when the return status is `error`. throw throwRetryableError( From 82376d66d171a6ca8851a5570e565a2bb4b8eab1 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 23 Mar 2023 07:14:45 -0400 Subject: [PATCH 14/17] Add logger assertions back into unit tests --- .../plugins/actions/server/lib/task_runner_factory.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts index d1a638cce5501..eae6cd5bc06c2 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts @@ -863,6 +863,9 @@ test(`will throw an error with retry: false if the task is not retryable`, async } expect(err).toBeDefined(); expect(isRetryableError(err)).toEqual(false); + expect(taskRunnerFactoryInitializerParams.logger.error as jest.Mock).toHaveBeenCalledWith( + `Action '2' failed: Error message` + ); }); test('will rethrow the error if the error is thrown instead of returned', async () => { @@ -900,6 +903,9 @@ test('will rethrow the error if the error is thrown instead of returned', async err = e; } expect(err).toBeDefined(); + expect(taskRunnerFactoryInitializerParams.logger.error as jest.Mock).toHaveBeenCalledWith( + `Action '2' failed: Fail` + ); expect(thrownError).toEqual(err); }); From 78846e4250218b2902f90a1aced2adc3079b68d2 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 23 Mar 2023 07:34:14 -0400 Subject: [PATCH 15/17] Speed up polling cycle --- x-pack/plugins/task_manager/server/polling_lifecycle.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/task_manager/server/polling_lifecycle.ts b/x-pack/plugins/task_manager/server/polling_lifecycle.ts index a0a626027c4d4..8b2149f8bfd10 100644 --- a/x-pack/plugins/task_manager/server/polling_lifecycle.ts +++ b/x-pack/plugins/task_manager/server/polling_lifecycle.ts @@ -271,15 +271,17 @@ export class TaskPollingLifecycle { // place tasks in the Task Pool async (tasks: TaskRunner[]) => { const tasksToRun = []; + const removeTaskPromises = []; for (const task of tasks) { if (task.isAdHocTaskAndOutOfAttempts) { this.logger.debug(`Removing ${task} because the max attempts have been reached.`); - await task.removeTask(); + removeTaskPromises.push(task.removeTask()); } else { tasksToRun.push(task); } } - const result = await this.pool.run(tasksToRun); + // Wait for all the promises at once to speed up the polling cycle + const [result] = await Promise.all([this.pool.run(tasksToRun), ...removeTaskPromises]); // Emit the load after fetching tasks, giving us a good metric for evaluating how // busy Task manager tends to be in this Kibana instance this.emitEvent(asTaskManagerStatEvent('load', asOk(this.pool.workerLoad))); From c7b4e7c81b05c0bef39977ef7575d6bd6f6f5951 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 24 Mar 2023 09:26:57 -0400 Subject: [PATCH 16/17] Revert "Use two different data archives" This reverts commit b0b3d68d5f8dfcbc9884407d47e17d2622a4b4db. --- .../tests/alerting/group4/run_soon.ts | 8 +- .../alerting/group4/scheduled_task_id.ts | 6 +- .../es_archives/rules_run_soon/data.json | 74 --- .../rules_scheduled_task_id/mappings.json | 460 ------------------ .../{ => rules}/data.json | 66 --- .../rules}/mappings.json | 116 ----- .../rules_scheduled_task_id/tasks/data.json | 65 +++ .../tasks/mappings.json | 115 +++++ 8 files changed, 189 insertions(+), 721 deletions(-) delete mode 100644 x-pack/test/functional/es_archives/rules_run_soon/data.json delete mode 100644 x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json rename x-pack/test/functional/es_archives/rules_scheduled_task_id/{ => rules}/data.json (58%) rename x-pack/test/functional/es_archives/{rules_run_soon => rules_scheduled_task_id/rules}/mappings.json (78%) create mode 100644 x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json create mode 100644 x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts index dc68f5f121fbd..3c0d6a41f2187 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -const LOADED_RULE_ID = 'c6b2c560-0685-42f6-b488-472594cfe915'; +const LOADED_RULE_ID = '74f3e6d7-b7bb-477d-ac28-92ee22728e6e'; // eslint-disable-next-line import/no-default-export export default function createRunSoonTests({ getService }: FtrProviderContext) { @@ -22,7 +22,8 @@ export default function createRunSoonTests({ getService }: FtrProviderContext) { const objectRemover = new ObjectRemover(supertest); before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rules_run_soon'); + await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); + await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); }); afterEach(async () => { @@ -30,7 +31,8 @@ export default function createRunSoonTests({ getService }: FtrProviderContext) { }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/rules_run_soon'); + await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); + await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); }); it('should successfully run rule where scheduled task id is different than rule id', async () => { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts index b7ad0e47947e1..1cedd3871d03e 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts @@ -36,11 +36,13 @@ export default function createScheduledTaskIdTests({ getService }: FtrProviderCo } before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id'); + await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); + await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id'); + await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); + await esArchiver.unload('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); }); it('cannot create rule with same ID as a scheduled task ID used by another rule', async () => { diff --git a/x-pack/test/functional/es_archives/rules_run_soon/data.json b/x-pack/test/functional/es_archives/rules_run_soon/data.json deleted file mode 100644 index 8a9041ee938ac..0000000000000 --- a/x-pack/test/functional/es_archives/rules_run_soon/data.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "type": "doc", - "value": { - "id": "alert:c6b2c560-0685-42f6-b488-472594cfe915", - "index": ".kibana_1", - "source": { - "alert": { - "actions": [ - ], - "alertTypeId": "example.always-firing", - "apiKey": "QIUT8u0/kbOakEHSj50jDpVR90MrqOxanEscboYOoa8PxQvcA5jfHash+fqH3b+KNjJ1LpnBcisGuPkufY9j1e32gKzwGZV5Bfys87imHvygJvIM8uKiFF8bQ8Y4NTaxOJO9fAmZPrFy07ZcQMCAQz+DUTgBFqs=", - "apiKeyOwner": "elastic", - "consumer": "alerts", - "createdAt": "2020-06-17T15:35:38.497Z", - "createdBy": "elastic", - "enabled": true, - "muteAll": false, - "mutedInstanceIds": [ - ], - "name": "always-firing-alert", - "params": { - }, - "schedule": { - "interval": "1m" - }, - "scheduledTaskId": "329798f0-b0b0-11ea-9510-fdf248d5f2a4", - "tags": [ - ], - "throttle": null, - "updatedBy": "elastic" - }, - "migrationVersion": { - "alert": "7.16.0" - }, - "references": [ - ], - "type": "alert", - "updated_at": "2020-06-17T15:35:39.839Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "task:329798f0-b0b0-11ea-9510-fdf248d5f2a4", - "index": ".kibana_task_manager_1", - "source": { - "migrationVersion": { - "task": "7.16.0" - }, - "task": { - "attempts": 0, - "ownerId": null, - "params": "{\"alertId\":\"c6b2c560-0685-42f6-b488-472594cfe915\",\"spaceId\":\"default\"}", - "retryAt": null, - "runAt": "2021-11-05T16:21:52.148Z", - "schedule": { - "interval": "1m" - }, - "scheduledAt": "2021-11-05T15:28:42.055Z", - "scope": [ - "alerting" - ], - "startedAt": null, - "status": "idle", - "taskType": "alerting:example.always-firing" - }, - "references": [], - "type": "task", - "updated_at": "2021-11-05T16:21:37.629Z" - } - } -} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json deleted file mode 100644 index 45adfd491a09b..0000000000000 --- a/x-pack/test/functional/es_archives/rules_scheduled_task_id/mappings.json +++ /dev/null @@ -1,460 +0,0 @@ -{ - "type": "index", - "value": { - "aliases": { - ".kibana": { - } - }, - "index": ".kibana_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "action": "6e96ac5e648f57523879661ea72525b7", - "action_task_params": "a9d49f184ee89641044be0ca2950fa3a", - "alert": "7b44fba6773e37c806ce290ea9b7024e", - "apm-indices": "9bb9b2bf1fa636ed8619cbab5ce6a1dd", - "apm-telemetry": "3525d7c22c42bc80f5e6e9cb3f2b26a2", - "application_usage_totals": "c897e4310c5f24b07caaff3db53ae2c1", - "application_usage_transactional": "965839e75f809fefe04f92dc4d99722a", - "canvas-element": "7390014e1091044523666d97247392fc", - "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", - "cases": "32aa96a6d3855ddda53010ae2048ac22", - "cases-comments": "c2061fb929f585df57425102fa928b4b", - "cases-configure": "42711cbb311976c0687853f4c1354572", - "cases-user-actions": "32277330ec6b721abe3b846cfd939a71", - "config": "ae24d22d5986d04124cc6568f771066f", - "dashboard": "d00f614b29a80360e1190193fd333bab", - "file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e", - "graph-workspace": "cd7ba1330e6682e9cc00b78850874be1", - "index-pattern": "66eccb05066c5a89924f48a9e9736499", - "infrastructure-ui-source": "ddc0ecb18383f6b26101a2fadb2dab0c", - "inventory-view": "88fc7e12fd1b45b6f0787323ce4f18d2", - "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", - "lens": "d33c68a69ff1e78c9888dedd2164ac22", - "lens-ui-telemetry": "509bfa5978586998e05f9e303c07a327", - "map": "23d7aa4a720d4938ccde3983f87bd58d", - "maps-telemetry": "bfd39d88aadadb4be597ea984d433dbe", - "metrics-explorer-view": "428e319af3e822c80a84cf87123ca35c", - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", - "search": "181661168bbadd1eff5902361e2a0d5c", - "space": "c5ca8acafa0beaa4d08d014a97b6bc6b", - "telemetry": "36a616f7026dfa617d6655df850fe16d", - "todo": "082a2cc96a590268344d5cd74c159ac4", - "tsvb-validation-telemetry": "3a37ef6c8700ae6fc97d5c7da00e9215", - "type": "2f4316de49999235636386fe51dc06c1", - "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0", - "upgrade-assistant-reindex-operation": "296a89039fc4260292be36b1b005d8f2", - "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", - "uptime-dynamic-settings": "fcdb453a30092f022f2642db29523d80", - "url": "b675c3be8d76ecf029294d51dc7ec65d", - "visualization": "52d7a13ad68a150c4525b292d23e12cc" - } - }, - "dynamic": "strict", - "properties": { - "action": { - "properties": { - "actionTypeId": { - "type": "keyword" - }, - "config": { - "enabled": false, - "type": "object" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - }, - "secrets": { - "type": "binary" - } - } - }, - "action_task_params": { - "properties": { - "actionId": { - "type": "keyword" - }, - "apiKey": { - "type": "binary" - }, - "params": { - "enabled": false, - "type": "object" - } - } - }, - "alert": { - "properties": { - "actions": { - "properties": { - "actionRef": { - "type": "keyword" - }, - "actionTypeId": { - "type": "keyword" - }, - "group": { - "type": "keyword" - }, - "params": { - "enabled": false, - "type": "object" - } - }, - "type": "nested" - }, - "alertTypeId": { - "type": "keyword" - }, - "apiKey": { - "type": "binary" - }, - "apiKeyOwner": { - "type": "keyword" - }, - "consumer": { - "type": "keyword" - }, - "createdAt": { - "type": "date" - }, - "createdBy": { - "type": "keyword" - }, - "enabled": { - "type": "boolean" - }, - "muteAll": { - "type": "boolean" - }, - "mutedInstanceIds": { - "type": "keyword" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - }, - "params": { - "enabled": false, - "type": "object" - }, - "schedule": { - "properties": { - "interval": { - "type": "keyword" - } - } - }, - "scheduledTaskId": { - "type": "keyword" - }, - "tags": { - "type": "keyword" - }, - "throttle": { - "type": "keyword" - }, - "updatedBy": { - "type": "keyword" - } - } - }, - "config": { - "dynamic": "true", - "properties": { - "buildNum": { - "type": "keyword" - } - } - }, - "migrationVersion": { - "dynamic": "true", - "properties": { - "alert": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "config": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "space": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "namespace": { - "type": "keyword" - }, - "namespaces": { - "type": "keyword" - }, - "query": { - "properties": { - "description": { - "type": "text" - }, - "filters": { - "enabled": false, - "type": "object" - }, - "query": { - "properties": { - "language": { - "type": "keyword" - }, - "query": { - "index": false, - "type": "keyword" - } - } - }, - "timefilter": { - "enabled": false, - "type": "object" - }, - "title": { - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "search": { - "properties": { - "columns": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "hits": { - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "sort": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "space": { - "properties": { - "_reserved": { - "type": "boolean" - }, - "color": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "disabledFeatures": { - "type": "keyword" - }, - "imageUrl": { - "index": false, - "type": "text" - }, - "initials": { - "type": "keyword" - }, - "name": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "1", - "number_of_shards": "1" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - ".kibana_task_manager": { - } - }, - "index": ".kibana_task_manager_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "originId": "2f4316de49999235636386fe51dc06c1", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "task": "235412e52d09e7165fac8a67a43ad6b4", - "type": "2f4316de49999235636386fe51dc06c1", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0" - } - }, - "dynamic": "strict", - "properties": { - "migrationVersion": { - "dynamic": "true", - "properties": { - "task": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "task": { - "properties": { - "attempts": { - "type": "integer" - }, - "ownerId": { - "type": "keyword" - }, - "params": { - "type": "text" - }, - "retryAt": { - "type": "date" - }, - "runAt": { - "type": "date" - }, - "schedule": { - "properties": { - "interval": { - "type": "keyword" - } - } - }, - "scheduledAt": { - "type": "date" - }, - "scope": { - "type": "keyword" - }, - "startedAt": { - "type": "date" - }, - "state": { - "type": "text" - }, - "status": { - "type": "keyword" - }, - "taskType": { - "type": "keyword" - }, - "user": { - "type": "keyword" - } - } - }, - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/data.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/data.json similarity index 58% rename from x-pack/test/functional/es_archives/rules_scheduled_task_id/data.json rename to x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/data.json index 25032f09eeb51..6cbc4d402f87d 100644 --- a/x-pack/test/functional/es_archives/rules_scheduled_task_id/data.json +++ b/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/data.json @@ -40,39 +40,6 @@ } } -{ - "type": "doc", - "value": { - "id": "task:329798f0-b0b0-11ea-9510-fdf248d5f2a4", - "index": ".kibana_task_manager_1", - "source": { - "migrationVersion": { - "task": "7.16.0" - }, - "task": { - "attempts": 0, - "ownerId": null, - "params": "{\"alertId\":\"74f3e6d7-b7bb-477d-ac28-92ee22728e6e\",\"spaceId\":\"default\"}", - "retryAt": null, - "runAt": "2021-11-05T16:21:52.148Z", - "schedule": { - "interval": "1m" - }, - "scheduledAt": "2021-11-05T15:28:42.055Z", - "scope": [ - "alerting" - ], - "startedAt": null, - "status": "idle", - "taskType": "alerting:example.always-firing" - }, - "references": [], - "type": "task", - "updated_at": "2021-11-05T16:21:37.629Z" - } - } -} - { "type": "doc", "value": { @@ -114,36 +81,3 @@ } } } - -{ - "type": "doc", - "value": { - "id": "task:46be60d4-ae63-48ed-ab6f-f4d9b4defacf", - "index": ".kibana_task_manager_1", - "source": { - "migrationVersion": { - "task": "7.16.0" - }, - "task": { - "attempts": 0, - "ownerId": null, - "params": "{\"alertId\":\"46be60d4-ae63-48ed-ab6f-f4d9b4defacf\",\"spaceId\":\"default\"}", - "retryAt": null, - "runAt": "2021-11-05T16:21:52.148Z", - "schedule": { - "interval": "1m" - }, - "scheduledAt": "2021-11-05T15:28:42.055Z", - "scope": [ - "alerting" - ], - "startedAt": null, - "status": "idle", - "taskType": "sampleTaskRemovedType" - }, - "references": [], - "type": "task", - "updated_at": "2021-11-05T16:21:37.629Z" - } - } -} diff --git a/x-pack/test/functional/es_archives/rules_run_soon/mappings.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/mappings.json similarity index 78% rename from x-pack/test/functional/es_archives/rules_run_soon/mappings.json rename to x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/mappings.json index 45adfd491a09b..babc00babc838 100644 --- a/x-pack/test/functional/es_archives/rules_run_soon/mappings.json +++ b/x-pack/test/functional/es_archives/rules_scheduled_task_id/rules/mappings.json @@ -342,119 +342,3 @@ } } } - -{ - "type": "index", - "value": { - "aliases": { - ".kibana_task_manager": { - } - }, - "index": ".kibana_task_manager_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "originId": "2f4316de49999235636386fe51dc06c1", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "task": "235412e52d09e7165fac8a67a43ad6b4", - "type": "2f4316de49999235636386fe51dc06c1", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0" - } - }, - "dynamic": "strict", - "properties": { - "migrationVersion": { - "dynamic": "true", - "properties": { - "task": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "task": { - "properties": { - "attempts": { - "type": "integer" - }, - "ownerId": { - "type": "keyword" - }, - "params": { - "type": "text" - }, - "retryAt": { - "type": "date" - }, - "runAt": { - "type": "date" - }, - "schedule": { - "properties": { - "interval": { - "type": "keyword" - } - } - }, - "scheduledAt": { - "type": "date" - }, - "scope": { - "type": "keyword" - }, - "startedAt": { - "type": "date" - }, - "state": { - "type": "text" - }, - "status": { - "type": "keyword" - }, - "taskType": { - "type": "keyword" - }, - "user": { - "type": "keyword" - } - } - }, - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json new file mode 100644 index 0000000000000..c71e4d14cf72d --- /dev/null +++ b/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/data.json @@ -0,0 +1,65 @@ +{ + "type": "doc", + "value": { + "id": "task:329798f0-b0b0-11ea-9510-fdf248d5f2a4", + "index": ".kibana_task_manager_1", + "source": { + "migrationVersion": { + "task": "7.16.0" + }, + "task": { + "attempts": 0, + "ownerId": null, + "params": "{\"alertId\":\"74f3e6d7-b7bb-477d-ac28-92ee22728e6e\",\"spaceId\":\"default\"}", + "retryAt": null, + "runAt": "2021-11-05T16:21:52.148Z", + "schedule": { + "interval": "1m" + }, + "scheduledAt": "2021-11-05T15:28:42.055Z", + "scope": [ + "alerting" + ], + "startedAt": null, + "status": "idle", + "taskType": "alerting:example.always-firing" + }, + "references": [], + "type": "task", + "updated_at": "2021-11-05T16:21:37.629Z" + } + } +} + +{ + "type": "doc", + "value": { + "id": "task:46be60d4-ae63-48ed-ab6f-f4d9b4defacf", + "index": ".kibana_task_manager_1", + "source": { + "migrationVersion": { + "task": "7.16.0" + }, + "task": { + "attempts": 0, + "ownerId": null, + "params": "{\"alertId\":\"46be60d4-ae63-48ed-ab6f-f4d9b4defacf\",\"spaceId\":\"default\"}", + "retryAt": null, + "runAt": "2021-11-05T16:21:52.148Z", + "schedule": { + "interval": "1m" + }, + "scheduledAt": "2021-11-05T15:28:42.055Z", + "scope": [ + "alerting" + ], + "startedAt": null, + "status": "idle", + "taskType": "sampleTaskRemovedType" + }, + "references": [], + "type": "task", + "updated_at": "2021-11-05T16:21:37.629Z" + } + } +} diff --git a/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json b/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json new file mode 100644 index 0000000000000..265d017bd72dc --- /dev/null +++ b/x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks/mappings.json @@ -0,0 +1,115 @@ +{ + "type": "index", + "value": { + "aliases": { + ".kibana_task_manager": { + } + }, + "index": ".kibana_task_manager_1", + "mappings": { + "_meta": { + "migrationMappingPropertyHashes": { + "migrationVersion": "4a1746014a75ade3a714e1db5763276f", + "namespace": "2f4316de49999235636386fe51dc06c1", + "namespaces": "2f4316de49999235636386fe51dc06c1", + "originId": "2f4316de49999235636386fe51dc06c1", + "references": "7997cf5a56cc02bdc9c93361bde732b0", + "task": "235412e52d09e7165fac8a67a43ad6b4", + "type": "2f4316de49999235636386fe51dc06c1", + "updated_at": "00da57df13e94e9d98437d13ace4bfe0" + } + }, + "dynamic": "strict", + "properties": { + "migrationVersion": { + "dynamic": "true", + "properties": { + "task": { + "fields": { + "keyword": { + "ignore_above": 256, + "type": "keyword" + } + }, + "type": "text" + } + } + }, + "references": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + }, + "type": { + "type": "keyword" + } + }, + "type": "nested" + }, + "task": { + "properties": { + "attempts": { + "type": "integer" + }, + "ownerId": { + "type": "keyword" + }, + "params": { + "type": "text" + }, + "retryAt": { + "type": "date" + }, + "runAt": { + "type": "date" + }, + "schedule": { + "properties": { + "interval": { + "type": "keyword" + } + } + }, + "scheduledAt": { + "type": "date" + }, + "scope": { + "type": "keyword" + }, + "startedAt": { + "type": "date" + }, + "state": { + "type": "text" + }, + "status": { + "type": "keyword" + }, + "taskType": { + "type": "keyword" + }, + "user": { + "type": "keyword" + } + } + }, + "type": { + "type": "keyword" + }, + "updated_at": { + "type": "date" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "number_of_replicas": "0", + "number_of_shards": "1" + } + } + } +} From 74c2a70ffffe95284c139d672ef3d97b8fd4b742 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 24 Mar 2023 09:28:30 -0400 Subject: [PATCH 17/17] Add comments --- .../spaces_only/tests/alerting/group4/run_soon.ts | 3 +++ .../spaces_only/tests/alerting/group4/scheduled_task_id.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts index 3c0d6a41f2187..beff33120922d 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/run_soon.ts @@ -22,6 +22,9 @@ export default function createRunSoonTests({ getService }: FtrProviderContext) { const objectRemover = new ObjectRemover(supertest); before(async () => { + // Not 100% sure why, seems the rules need to be loaded separately to avoid the task + // failing to load the rule during execution and deleting itself. Otherwise + // we have flakiness await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts index 1cedd3871d03e..a22246224d5c2 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/scheduled_task_id.ts @@ -36,6 +36,9 @@ export default function createScheduledTaskIdTests({ getService }: FtrProviderCo } before(async () => { + // Not 100% sure why, seems the rules need to be loaded separately to avoid the task + // failing to load the rule during execution and deleting itself. Otherwise + // we have flakiness await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/rules'); await esArchiver.load('x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks'); });