Skip to content

Commit 0651cb1

Browse files
Merge master into feature/cw-proactive-scan
2 parents 8cc11a0 + 1bdd6ca commit 0651cb1

File tree

2 files changed

+42
-6
lines changed

2 files changed

+42
-6
lines changed

packages/core/src/amazonqFeatureDev/storages/chatSession.ts

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

6+
import AsyncLock from 'async-lock'
67
import { Messenger } from '../controllers/chat/messenger/messenger'
78
import { Session } from '../session/session'
89
import { createSessionConfig } from '../session/sessionConfigFactory'
910

1011
export class ChatSessionStorage {
12+
private lock = new AsyncLock()
13+
1114
private sessions: Map<string, Session> = new Map()
1215

1316
constructor(private readonly messenger: Messenger) {}
@@ -20,12 +23,19 @@ export class ChatSessionStorage {
2023
}
2124

2225
public async getSession(tabID: string): Promise<Session> {
23-
const sessionFromStorage = this.sessions.get(tabID)
24-
if (sessionFromStorage === undefined) {
25-
// If a session doesn't already exist just create it
26-
return this.createSession(tabID)
27-
}
28-
return sessionFromStorage
26+
/**
27+
* The lock here is added in order to mitigate amazon Q's eventing fire & forget design when integrating with mynah-ui that creates a race condition here.
28+
* The race condition happens when handleDevFeatureCommand in src/amazonq/webview/ui/quickActions/handler.ts is firing two events after each other to amazonqFeatureDev controller
29+
* This eventually may make code generation fail as at the moment of that event it may get from the storage a session that has not been properly updated.
30+
*/
31+
return this.lock.acquire(tabID, async () => {
32+
const sessionFromStorage = this.sessions.get(tabID)
33+
if (sessionFromStorage === undefined) {
34+
// If a session doesn't already exist just create it
35+
return this.createSession(tabID)
36+
}
37+
return sessionFromStorage
38+
})
2939
}
3040

3141
// Find all sessions that are currently waiting to be authenticated
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
import * as assert from 'assert'
6+
7+
import { Messenger } from '../../../amazonqFeatureDev/controllers/chat/messenger/messenger'
8+
import { ChatSessionStorage } from '../../../amazonqFeatureDev/storages/chatSession'
9+
import { createMessenger } from '../utils'
10+
11+
describe('chatSession', () => {
12+
const tabID = '1234'
13+
let chatStorage: ChatSessionStorage
14+
let messenger: Messenger
15+
16+
beforeEach(() => {
17+
messenger = createMessenger()
18+
chatStorage = new ChatSessionStorage(messenger)
19+
})
20+
21+
it('locks getSession', async () => {
22+
const results = await Promise.allSettled([chatStorage.getSession(tabID), chatStorage.getSession(tabID)])
23+
assert.equal(results.length, 2)
24+
assert.deepStrictEqual(results[0], results[1])
25+
})
26+
})

0 commit comments

Comments
 (0)