@@ -11,6 +11,11 @@ import ConnectionString from 'mongodb-connection-string-url';
1111import { createServiceProvider } from 'hadron-app-registry' ;
1212import type { AtlasService } from '@mongodb-js/atlas-service/provider' ;
1313import { atlasServiceLocator } from '@mongodb-js/atlas-service/provider' ;
14+ import {
15+ mongoLogId ,
16+ useLogger ,
17+ type Logger ,
18+ } from '@mongodb-js/compass-logging/provider' ;
1419
1520type ElectableSpecs = {
1621 instanceSize ?: string ;
@@ -156,7 +161,7 @@ export function buildConnectionInfoFromClusterDescription(
156161 description : ClusterDescriptionWithDataProcessingRegion ,
157162 deployment : Deployment ,
158163 extraConnectionOptions ?: Record < string , any >
159- ) {
164+ ) : ConnectionInfo {
160165 const connectionString = new ConnectionString (
161166 `mongodb+srv://${ description . srvAddress } `
162167 ) ;
@@ -221,7 +226,10 @@ export function buildConnectionInfoFromClusterDescription(
221226 } ;
222227}
223228
224- class AtlasCloudConnectionStorage
229+ /**
230+ * @internal exported for testing purposes
231+ */
232+ export class AtlasCloudConnectionStorage
225233 extends InMemoryConnectionStorage
226234 implements ConnectionStorage
227235{
@@ -230,6 +238,7 @@ class AtlasCloudConnectionStorage
230238 private atlasService : AtlasService ,
231239 private orgId : string ,
232240 private projectId : string ,
241+ private logger : Logger ,
233242 private extraConnectionOptions ?: Record < string , any >
234243 ) {
235244 super ( ) ;
@@ -249,67 +258,95 @@ class AtlasCloudConnectionStorage
249258 // TODO(CLOUDP-249088): replace with the list request that already
250259 // contains regional data when it exists instead of fetching
251260 // one-by-one after the list fetch
252- this . atlasService . cloudEndpoint ( `nds/clusters/${ this . projectId } ` )
261+ this . atlasService . cloudEndpoint ( `/ nds/clusters/${ this . projectId } ` )
253262 )
254263 . then ( ( res ) => {
255264 return res . json ( ) as Promise < ClusterDescription [ ] > ;
256265 } )
257266 . then ( ( descriptions ) => {
258267 return Promise . all (
259- descriptions
260- . filter ( ( description ) => {
261- // Only list fully deployed clusters
262- // TODO(COMPASS-8228): We should probably list all and just
263- // account in the UI for a special state of a deployment as
264- // clusters can become inactive during their runtime and it's
265- // valuable UI info to display
266- return ! description . isPaused && ! ! description . srvAddress ;
267- } )
268- . map ( async ( description ) => {
269- // Even though nds/clusters will list serverless clusters, to get
270- // the regional description we need to change the url
271- const clusterDescriptionType = isServerless ( description )
272- ? 'serverless'
273- : 'clusters' ;
268+ descriptions . map ( async ( description ) => {
269+ // Even though nds/clusters will list serverless clusters, to get
270+ // the regional description we need to change the url
271+ const clusterDescriptionType = isServerless ( description )
272+ ? 'serverless'
273+ : 'clusters' ;
274+ try {
274275 const res = await this . atlasService . authenticatedFetch (
275276 this . atlasService . cloudEndpoint (
276- `nds/${ clusterDescriptionType } /${ this . projectId } /${ description . name } /regional/clusterDescription`
277+ `/ nds/${ clusterDescriptionType } /${ this . projectId } /${ description . name } /regional/clusterDescription`
277278 )
278279 ) ;
279280 return await ( res . json ( ) as Promise < ClusterDescriptionWithDataProcessingRegion > ) ;
280- } )
281+ } catch ( err ) {
282+ this . logger . log . error (
283+ mongoLogId ( 1_001_000_303 ) ,
284+ 'LoadAndNormalizeClusterDescriptionInfo' ,
285+ 'Failed to fetch cluster description for cluster' ,
286+ { clusterName : description . name , error : ( err as Error ) . stack }
287+ ) ;
288+ return null ;
289+ }
290+ } )
281291 ) ;
282292 } ) ,
283293 this . atlasService
284294 . authenticatedFetch (
285- this . atlasService . cloudEndpoint ( `deployment/${ this . projectId } ` )
295+ this . atlasService . cloudEndpoint ( `/ deployment/${ this . projectId } ` )
286296 )
287297 . then ( ( res ) => {
288298 return res . json ( ) as Promise < Deployment > ;
289299 } ) ,
290300 ] ) ;
291301
292- return clusterDescriptions . map ( ( description ) => {
293- return buildConnectionInfoFromClusterDescription (
294- this . atlasService . driverProxyEndpoint (
295- `/clusterConnection/${ this . projectId } `
296- ) ,
297- this . orgId ,
298- this . projectId ,
299- description ,
300- deployment ,
301- this . extraConnectionOptions
302- ) ;
303- } ) ;
302+ return clusterDescriptions
303+ . map ( ( description ) => {
304+ // Clear cases where cluster doesn't have enough metadata
305+ // - Failed to get the description
306+ // - Cluster is paused
307+ // - Cluster is missing an srv address (happens during deployment /
308+ // termination)
309+ if ( ! description || ! ! description . isPaused || ! description . srvAddress ) {
310+ return null ;
311+ }
312+
313+ try {
314+ // We will always try to build the metadata, it can fail if deployment
315+ // item for the cluster is missing even when description exists
316+ // (happens during deployment / termination / weird corner cases of
317+ // atlas cluster state)
318+ return buildConnectionInfoFromClusterDescription (
319+ this . atlasService . driverProxyEndpoint (
320+ `/clusterConnection/${ this . projectId } `
321+ ) ,
322+ this . orgId ,
323+ this . projectId ,
324+ description ,
325+ deployment ,
326+ this . extraConnectionOptions
327+ ) ;
328+ } catch ( err ) {
329+ this . logger . log . error (
330+ mongoLogId ( 1_001_000_304 ) ,
331+ 'LoadAndNormalizeClusterDescriptionInfo' ,
332+ 'Failed to build connection info from cluster description' ,
333+ { clusterName : description . name , error : ( err as Error ) . stack }
334+ ) ;
335+
336+ return null ;
337+ }
338+ } )
339+ . filter ( ( connectionInfo ) : connectionInfo is ConnectionInfo => {
340+ return ! ! connectionInfo ;
341+ } ) ;
304342 }
305343
306- async loadAll ( ) : Promise < ConnectionInfo [ ] > {
307- try {
308- return ( this . loadAllPromise ??=
309- this . _loadAndNormalizeClusterDescriptionInfo ( ) ) ;
310- } finally {
311- delete this . loadAllPromise ;
312- }
344+ loadAll ( ) : Promise < ConnectionInfo [ ] > {
345+ this . loadAllPromise ??=
346+ this . _loadAndNormalizeClusterDescriptionInfo ( ) . finally ( ( ) => {
347+ delete this . loadAllPromise ;
348+ } ) ;
349+ return this . loadAllPromise ;
313350 }
314351}
315352
@@ -358,12 +395,14 @@ export const AtlasCloudConnectionStorageProvider = createServiceProvider(
358395 const extraConnectionOptions = useContext (
359396 SandboxExtraConnectionOptionsContext
360397 ) ;
398+ const logger = useLogger ( 'ATLAS-CLOUD-CONNECTION-STORAGE' ) ;
361399 const atlasService = atlasServiceLocator ( ) ;
362400 const storage = useRef (
363401 new AtlasCloudConnectionStorage (
364402 atlasService ,
365403 orgId ,
366404 projectId ,
405+ logger ,
367406 extraConnectionOptions
368407 )
369408 ) ;
0 commit comments