diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index efbe7b8b2a2..339c34d03b8 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -4,7 +4,7 @@ run-name: ${{ github.actor }} is running Deploy CD on: push: branches: # White-list of deployable tags and branches. Note that all white-listed branches cannot include any `/` characters - - next + - webex-services-ready env: rid: ${{ github.run_id }}-${{ github.run_number }} diff --git a/packages/@webex/webex-core/src/lib/services-v2/services-v2.ts b/packages/@webex/webex-core/src/lib/services-v2/services-v2.ts index 118c4d230fd..6e072da74c9 100644 --- a/packages/@webex/webex-core/src/lib/services-v2/services-v2.ts +++ b/packages/@webex/webex-core/src/lib/services-v2/services-v2.ts @@ -40,6 +40,20 @@ const Services = WebexPlugin.extend({ initFailed: ['boolean', false, false], }, + session: { + /** + * Becomes `true` once services initialization has completed. + * This blocks `webex.ready` until services are initialized. + * @instance + * @memberof Services + * @type {boolean} + */ + ready: { + default: false, + type: 'boolean', + }, + }, + _catalogs: new WeakMap(), _activeServices: {}, @@ -1091,9 +1105,10 @@ const Services = WebexPlugin.extend({ this.initConfig(); }); - // wait for webex instance to be ready before attempting - // to update the service catalogs - this.listenToOnce(this.webex, 'ready', () => { + // wait for webex instance storage to be loaded before attempting + // to update the service catalogs. Using 'loaded' instead of 'ready' + // to avoid deadlock since webex.ready depends on this plugin's ready. + this.listenToOnce(this.webex, 'loaded', () => { const {supertoken} = this.webex.credentials; // Validate if the supertoken exists. if (supertoken && supertoken.access_token) { @@ -1106,16 +1121,25 @@ const Services = WebexPlugin.extend({ this.logger.error( `services: failed to init initial services when credentials available, ${error?.message}` ); + }) + .finally(() => { + this.ready = true; + this.trigger('services:initialized'); }); } else { const {email} = this.webex.config; - this.collectPreauthCatalog(email ? {email} : undefined).catch((error) => { - this.initFailed = true; - this.logger.error( - `services: failed to init initial services when no credentials available, ${error?.message}` - ); - }); + this.collectPreauthCatalog(email ? {email} : undefined) + .catch((error) => { + this.initFailed = true; + this.logger.error( + `services: failed to init initial services when no credentials available, ${error?.message}` + ); + }) + .finally(() => { + this.ready = true; + this.trigger('services:initialized'); + }); } }); }, diff --git a/packages/@webex/webex-core/src/lib/services/services.js b/packages/@webex/webex-core/src/lib/services/services.js index 32f3120dcea..74c7280dfd2 100644 --- a/packages/@webex/webex-core/src/lib/services/services.js +++ b/packages/@webex/webex-core/src/lib/services/services.js @@ -55,6 +55,20 @@ const Services = WebexPlugin.extend({ initFailed: ['boolean', false, false], }, + session: { + /** + * Becomes `true` once service catalog initialization has completed. + * Blocks `webex.ready` until services are initialized. + * @instance + * @memberof Services + * @type {boolean} + */ + ready: { + default: false, + type: 'boolean', + }, + }, + _catalogs: new WeakMap(), _serviceUrls: null, @@ -1121,9 +1135,10 @@ const Services = WebexPlugin.extend({ this.initConfig(); }); - // wait for webex instance to be ready before attempting - // to update the service catalogs - this.listenToOnce(this.webex, 'ready', () => { + // Wait for storage to be loaded before attempting to update the service catalogs. + // We listen for 'loaded' instead of 'ready' because services.ready is a dependency + // of webex.ready - listening to 'ready' would cause a deadlock. + this.listenToOnce(this.webex, 'loaded', () => { const {supertoken} = this.webex.credentials; // Validate if the supertoken exists. if (supertoken && supertoken.access_token) { @@ -1136,16 +1151,25 @@ const Services = WebexPlugin.extend({ this.logger.error( `services: failed to init initial services when credentials available, ${error?.message}` ); + }) + .finally(() => { + this.ready = true; + this.trigger('services:initialized'); }); } else { const {email} = this.webex.config; - this.collectPreauthCatalog(email ? {email} : undefined).catch((error) => { - this.initFailed = true; - this.logger.error( - `services: failed to init initial services when no credentials available, ${error?.message}` - ); - }); + this.collectPreauthCatalog(email ? {email} : undefined) + .catch((error) => { + this.initFailed = true; + this.logger.error( + `services: failed to init initial services when no credentials available, ${error?.message}` + ); + }) + .finally(() => { + this.ready = true; + this.trigger('services:initialized'); + }); } }); },