import _ from 'lodash' ; import { SavedObjectsMigrationLogger } from './migration_logger' ; const DEFAULT_POLL_INTERVAL = 15000 ; export type MigrationStatus = 'waiting' | 'running' | 'completed' ; export type MigrationResult = { status : 'skipped' ; } | { status : 'patched' ; } | { status : 'migrated' ; destIndex : string ; sourceIndex : string ; elapsedMs : number ; } ; interface Opts { runMigration : ( ) => Promise < MigrationResult > ; isMigrated : ( ) => Promise < boolean > ; log : SavedObjectsMigrationLogger ; pollInterval ? : number ; } export param { Opts } opts prop prop prop prop returns export async function coordinateMigration ( opts ) { try { return await opts . runMigration ( ) ; } catch ( error ) { if ( handleIndexExists ( error , opts . log ) ) { await waitForMigration ( opts . isMigrated , opts . pollInterval ) ; return { status : 'skipped' } ; } throw error ; } } /**
 * If the specified error is an index exists error, this logs a warning,
 * and is the cue for us to fall into a polling loop, waiting for some
 * other OpenSearch Dashboards instance to complete the migration.
 */ function handleIndexExists ( error , log ) { const isIndexExistsError = _ . get ( error , 'body.error.type' ) === 'resource_already_exists_exception' ; if ( ! isIndexExistsError ) { return false ; } const index = _ . get ( error , 'body.error.index' ) ; log . warning ( `Another OpenSearch Dashboards instance appears to be migrating the index. Waiting for ` + `that migration to complete. If no other OpenSearch Dashboards instance is attempting ` + `migrations, you can get past this message by deleting index ${ index } and ` + `restarting OpenSearchDashboards.` ) ; return true ; } /**
 * Polls isMigrated every pollInterval milliseconds until it returns true.
 */ async function waitForMigration ( isMigrated , pollInterval = DEFAULT_POLL_INTERVAL ) { while ( true ) { if ( await isMigrated ( ) ) { return ; } await sleep ( pollInterval ) ; } } function sleep ( ms ) { return new Promise ( ( r ) => setTimeout ( r , ms ) ) ; }