1+ import { DescribeTypeOutput } from '@aws-sdk/client-cloudformation' ;
12import { DateTime } from 'luxon' ;
23import { SettingsConfigurable , ISettingsSubscriber , SettingsSubscription } from '../settings/ISettingsSubscriber' ;
34import { DefaultSettings , ProfileSettings } from '../settings/Settings' ;
45import { LoggerFactory } from '../telemetry/LoggerFactory' ;
56import { ScopedTelemetry } from '../telemetry/ScopedTelemetry' ;
6- import { Telemetry } from '../telemetry/TelemetryDecorator' ;
7+ import { Telemetry , Measure } from '../telemetry/TelemetryDecorator' ;
78import { Closeable } from '../utils/Closeable' ;
89import { AwsRegion , getRegion } from '../utils/Region' ;
910import { CombinedSchemas } from './CombinedSchemas' ;
1011import { GetSchemaTaskManager } from './GetSchemaTaskManager' ;
11- import { RegionalSchemasType } from './RegionalSchemas' ;
12+ import { PrivateSchemasType } from './PrivateSchemas' ;
13+ import { RegionalSchemasType , SchemaFileType } from './RegionalSchemas' ;
1214import { SamSchemasType , SamStoreKey } from './SamSchemas' ;
1315import { SchemaStore } from './SchemaStore' ;
1416
@@ -19,14 +21,24 @@ export class SchemaRetriever implements SettingsConfigurable, Closeable {
1921 private settingsSubscription ?: SettingsSubscription ;
2022 private settings : ProfileSettings = DefaultSettings . profile ;
2123 private readonly log = LoggerFactory . getLogger ( SchemaRetriever ) ;
24+ private readonly schemaTaskManager : GetSchemaTaskManager ;
2225
2326 @Telemetry ( )
2427 private readonly telemetry ! : ScopedTelemetry ;
2528
2629 constructor (
27- private readonly schemaTaskManager : GetSchemaTaskManager ,
2830 private readonly schemaStore : SchemaStore ,
31+ private readonly getPublicSchemas : ( region : AwsRegion ) => Promise < SchemaFileType [ ] > ,
32+ private readonly getPrivateResources : ( ) => Promise < DescribeTypeOutput [ ] > ,
2933 ) {
34+ this . schemaTaskManager = new GetSchemaTaskManager (
35+ this . schemaStore ,
36+ this . getPublicSchemas ,
37+ this . getPrivateResources ,
38+ this . settings . profile ,
39+ ( region , profile ) => this . rebuildAffectedCombinedSchemas ( region , profile ) ,
40+ ) ;
41+
3042 this . telemetry . registerGaugeProvider ( 'schema.public.maxAge' , ( ) => this . getPublicSchemaMaxAge ( ) , {
3143 unit : 'ms' ,
3244 } ) ;
@@ -84,15 +96,31 @@ export class SchemaRetriever implements SettingsConfigurable, Closeable {
8496 return this . get ( this . settings . region , this . settings . profile ) ;
8597 }
8698
99+ @Measure ( { name : 'getSchemas' } )
87100 get ( region : AwsRegion , profile : string ) : CombinedSchemas {
101+ // Check if combined schemas are already cached first
102+ const cacheKey = `${ region } :${ profile } ` ;
103+ const cachedCombined = this . schemaStore . combinedSchemas . get < CombinedSchemas > ( cacheKey ) ;
104+
105+ if ( cachedCombined ) {
106+ return cachedCombined ;
107+ }
108+
109+ // Only do expensive regional check if no cached combined schemas
88110 const regionalSchemas = this . getRegionalSchemasFromStore ( region ) ;
89111 if ( regionalSchemas ) {
90112 this . availableRegions . add ( region ) ;
91113 } else {
92114 this . schemaTaskManager . addTask ( region ) ;
93115 }
94116
95- return this . schemaStore . getCombinedSchemas ( region , profile ) ;
117+ // Create and cache combined schemas
118+ const privateSchemas = this . schemaStore . privateSchemas . get < PrivateSchemasType > ( profile ) ;
119+ const samSchemas = this . schemaStore . samSchemas . get < SamSchemasType > ( SamStoreKey ) ;
120+ const combinedSchemas = CombinedSchemas . from ( regionalSchemas , privateSchemas , samSchemas ) ;
121+
122+ void this . schemaStore . combinedSchemas . put ( cacheKey , combinedSchemas ) ;
123+ return combinedSchemas ;
96124 }
97125
98126 updatePrivateSchemas ( ) {
@@ -105,6 +133,34 @@ export class SchemaRetriever implements SettingsConfigurable, Closeable {
105133 this . schemaStore . invalidateCombinedSchemas ( ) ;
106134 }
107135
136+ // Proactively rebuild combined schemas to avoid lazy loading delays
137+ @Measure ( { name : 'rebuildCurrentSchemas' } )
138+ rebuildForCurrentSettings ( ) {
139+ this . schemaStore . invalidateCombinedSchemas ( ) ;
140+ this . get ( this . settings . region , this . settings . profile ) ;
141+ }
142+
143+ // Surgically rebuild affected combined schemas
144+ @Measure ( { name : 'rebuildAffectedSchemas' } )
145+ rebuildAffectedCombinedSchemas ( updatedRegion ?: string , updatedProfile ?: string ) {
146+ if ( ! updatedRegion && ! updatedProfile ) {
147+ // SAM update - affects all schemas
148+ this . schemaStore . invalidateCombinedSchemas ( ) ;
149+ this . rebuildForCurrentSettings ( ) ;
150+ return ;
151+ }
152+
153+ const keys = this . schemaStore . combinedSchemas . keys ( 1000 ) ;
154+ for ( const key of keys ) {
155+ const [ region , profile ] = key . split ( ':' ) ;
156+ if ( ( updatedRegion && region === updatedRegion ) || ( updatedProfile && profile === updatedProfile ) ) {
157+ // Invalidate and rebuild this specific combined schema
158+ void this . schemaStore . combinedSchemas . remove ( key ) ;
159+ this . get ( region as AwsRegion , profile ) ;
160+ }
161+ }
162+ }
163+
108164 private getRegionalSchemasFromStore ( region : AwsRegion ) {
109165 return this . schemaStore . publicSchemas . get < RegionalSchemasType > ( region ) ;
110166 }
0 commit comments