diff --git a/packages/kbn-lock-manager/src/lock_manager_client.ts b/packages/kbn-lock-manager/src/lock_manager_client.ts index 350711cad4268..74b9129ffdbfc 100644 --- a/packages/kbn-lock-manager/src/lock_manager_client.ts +++ b/packages/kbn-lock-manager/src/lock_manager_client.ts @@ -12,7 +12,6 @@ import { errors } from '@elastic/elasticsearch'; import { Logger } from '@kbn/logging'; import { v4 as uuid } from 'uuid'; import prettyMilliseconds from 'pretty-ms'; -import { once } from 'lodash'; import { duration } from 'moment'; import { ElasticsearchClient } from '@kbn/core/server'; import { LOCKS_CONCRETE_INDEX_NAME, setupLockManagerIndex } from './setup_lock_manager_index'; @@ -39,10 +38,21 @@ export interface AcquireOptions { } // The index assets should only be set up once +let runLockManagerSetupSuccessfully = false; +export const runSetupIndexAssetOnce = async ( + esClient: ElasticsearchClient, + logger: Logger +): Promise => { + if (runLockManagerSetupSuccessfully) { + return; + } + await setupLockManagerIndex(esClient, logger); + runLockManagerSetupSuccessfully = true; +}; + // For testing purposes, we need to be able to set it up every time -let runSetupIndexAssetOnce = once(setupLockManagerIndex); -export function runSetupIndexAssetEveryTime() { - runSetupIndexAssetOnce = setupLockManagerIndex; +export function rerunSetupIndexAsset() { + runLockManagerSetupSuccessfully = false; } export class LockManager { diff --git a/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/ai_assistant/distributed_lock_manager/distributed_lock_manager.spec.ts b/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/ai_assistant/distributed_lock_manager/distributed_lock_manager.spec.ts index b61c10a026c23..4cf29dc6730f5 100644 --- a/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/ai_assistant/distributed_lock_manager/distributed_lock_manager.spec.ts +++ b/x-pack/solutions/observability/test/api_integration_deployment_agnostic/apis/ai_assistant/distributed_lock_manager/distributed_lock_manager.spec.ts @@ -18,7 +18,7 @@ import { LockManager, LockDocument, withLock, - runSetupIndexAssetEveryTime, + rerunSetupIndexAsset, } from '@kbn/lock-manager/src/lock_manager_client'; import { LOCKS_COMPONENT_TEMPLATE_NAME, @@ -42,9 +42,11 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon before(async () => { // delete existing index mappings to ensure we start from a clean state await deleteLockIndexAssets(es, log); + }); + beforeEach(async () => { // ensure that the index and templates are created - runSetupIndexAssetEveryTime(); + rerunSetupIndexAsset(); }); after(async () => { @@ -804,6 +806,38 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon }); }); }); + + describe('setup robustness', () => { + it('should retry if setup fails the first time', async () => { + const brokenEsClient = { + ...es, + cluster: { + ...es.cluster, + putComponentTemplate: () => { + throw new Error('Simulated failure on first attempt'); + }, + }, + } as unknown as Client; + const brokenLockManager = new LockManager('test', brokenEsClient, logger); + const workingLockManager = new LockManager('test', es, logger); + let error; + try { + await brokenLockManager.acquire(); + } catch (e) { + error = e; + } + expect(error).to.be.an(Error); + + // if the the second attempt succeeds, it means it didn't get stuck on the first failure + error = undefined; + try { + await workingLockManager.acquire(); + } catch (e) { + error = e; + } + expect(error).to.be(undefined); + }); + }); }); }