Skip to content

Commit 9923793

Browse files
committed
fix(amazonq): Reduce plugin start-up latency
1 parent b39ab4e commit 9923793

File tree

5 files changed

+51
-12
lines changed

5 files changed

+51
-12
lines changed

packages/amazonq/src/extension.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { Auth, AuthUtils, CredentialsStore, LoginManager, initializeAuth } from 'aws-core-vscode/auth'
6+
import { AuthUtils, CredentialsStore, LoginManager, initializeAuth } from 'aws-core-vscode/auth'
77
import { activate as activateCodeWhisperer, shutdown as shutdownCodeWhisperer } from 'aws-core-vscode/codewhisperer'
88
import { makeEndpointsProvider, registerGenericCommands } from 'aws-core-vscode'
99
import { CommonAuthWebview } from 'aws-core-vscode/login'
@@ -44,7 +44,6 @@ import * as vscode from 'vscode'
4444
import { registerCommands } from './commands'
4545
import { focusAmazonQPanel } from 'aws-core-vscode/codewhispererChat'
4646
import { activate as activateAmazonqLsp } from './lsp/activation'
47-
import { activate as activateInlineCompletion } from './app/inline/activation'
4847
import { hasGlibcPatch } from './lsp/client'
4948

5049
export const amazonQContextPrefix = 'amazonq'
@@ -126,17 +125,11 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is
126125

127126
// This contains every lsp agnostic things (auth, security scan, code scan)
128127
await activateCodeWhisperer(extContext as ExtContext)
129-
if (
130-
(Experiments.instance.get('amazonqLSP', true) || Auth.instance.isInternalAmazonUser()) &&
131-
(!isAmazonLinux2() || hasGlibcPatch())
132-
) {
133-
// start the Amazon Q LSP for internal users first
134-
// for AL2, start LSP if glibc patch is found
128+
129+
if (!isAmazonLinux2() || hasGlibcPatch()) {
130+
// Activate Amazon Q LSP for everyone unless they're using AL2 without the glibc patch
135131
await activateAmazonqLsp(context)
136132
}
137-
if (!Experiments.instance.get('amazonqLSPInline', true)) {
138-
await activateInlineCompletion()
139-
}
140133

141134
// Generic extension commands
142135
registerGenericCommands(context, amazonQContextPrefix)

packages/core/src/codewhisperer/commands/basicCommands.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,12 @@ const registerToolkitApiCallbackOnce = once(() => {
634634
export const registerToolkitApiCallback = Commands.declare(
635635
{ id: 'aws.amazonq.refreshConnectionCallback' },
636636
() => async (toolkitApi?: any) => {
637+
// Early return if already registered to avoid duplicate work
638+
if (_toolkitApi) {
639+
getLogger().debug('Toolkit API callback already registered, skipping')
640+
return
641+
}
642+
637643
// While the Q/CW exposes an API for the Toolkit to register callbacks on auth changes,
638644
// we need to do it manually here because the Toolkit would have been unable to call
639645
// this API if the Q/CW extension started afterwards (and this code block is running).

packages/core/src/codewhisperer/region/regionProfileManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export class RegionProfileManager {
7777
result: undefined,
7878
},
7979
},
80-
{ timeout: 15000, interval: 1500, truthy: true }
80+
{ timeout: 15000, interval: 500, truthy: true }
8181
)
8282
}
8383

packages/core/src/shared/featureConfig.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ export const featureDefinitions = new Map<FeatureName, FeatureContext>([
5555

5656
export class FeatureConfigProvider {
5757
private featureConfigs = new Map<string, FeatureContext>()
58+
private fetchPromise: Promise<void> | undefined = undefined
59+
private lastFetchTime = 0
60+
private readonly minFetchInterval = 5000 // 5 seconds minimum between fetches
5861

5962
static #instance: FeatureConfigProvider
6063

@@ -123,6 +126,28 @@ export class FeatureConfigProvider {
123126
return
124127
}
125128

129+
// Debounce multiple concurrent calls
130+
const now = performance.now()
131+
if (this.fetchPromise && now - this.lastFetchTime < this.minFetchInterval) {
132+
getLogger().debug('amazonq: Debouncing feature config fetch')
133+
return this.fetchPromise
134+
}
135+
136+
if (this.fetchPromise) {
137+
return this.fetchPromise
138+
}
139+
140+
this.lastFetchTime = now
141+
this.fetchPromise = this._fetchFeatureConfigsInternal()
142+
143+
try {
144+
await this.fetchPromise
145+
} finally {
146+
this.fetchPromise = undefined
147+
}
148+
}
149+
150+
private async _fetchFeatureConfigsInternal(): Promise<void> {
126151
getLogger().debug('amazonq: Fetching feature configs')
127152
try {
128153
const response = await this.listFeatureEvaluations()

packages/core/src/shared/utilities/resourceCache.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,21 @@ export abstract class CachedResource<V> {
6060
abstract resourceProvider(): Promise<V>
6161

6262
async getResource(): Promise<V> {
63+
// Check cache without locking first
64+
const quickCheck = this.readCacheOrDefault()
65+
if (quickCheck.resource.result && !quickCheck.resource.locked) {
66+
const duration = now() - quickCheck.resource.timestamp
67+
if (duration < this.expirationInMilli) {
68+
logger.debug(
69+
`cache hit (fast path), duration(%sms) is less than expiration(%sms), returning cached value: %s`,
70+
duration,
71+
this.expirationInMilli,
72+
this.key
73+
)
74+
return quickCheck.resource.result
75+
}
76+
}
77+
6378
const cachedValue = await this.tryLoadResourceAndLock()
6479
const resource = cachedValue?.resource
6580

0 commit comments

Comments
 (0)