-
Notifications
You must be signed in to change notification settings - Fork 335
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding fixing save chat session overwriting #6457
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this! Left a comment in line, will do a proper review once I'm back on my computer later.
Would be great if we can have a test covering this behavior!
@@ -446,8 +446,10 @@ export class ChatsController implements vscode.Disposable { | |||
return | |||
} | |||
|
|||
// For single chat deletion | |||
await chatHistory.deleteChat(authStatus, chatID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't looked into the code yet but wonder if it would work if we dispose the chat before we deleting the chat?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be great if we can have a test covering this behavior!
So I could possibly write some kind of "number of times called" kind of test on chatcontroller but I would ideally love to have webview based UI test(see slack)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wonder if it would work if we dispose the chat before we deleting the chat?
While disposing before deleting seems like a good approach to prevent race conditions, it doesn't fully solve the problem. Here's why:
private async clearHistory(chatID?: string): Promise<void> {
// ... other code ...
// Even if we do this:
this.disposeChat(chatID, true) // Step 1: Dispose first
await chatHistory.deleteChat(authStatus, chatID) // Step 2: Then delete
// The issue is that disposeChat() itself triggers a save operation:
// 1. When disposing the chat controller
// 2. When clearing/restarting the session
The race condition still exists because:
disposeChat() triggers a save operation as part of its cleanup
Then we immediately try to delete the chat history
These operations can overlap since saves are asynchronous
That's why the current solution uses a skipSave flag:
this.disposeChat(chatID, true, { skipSave: true }) // Prevents the save during disposal
await chatHistory.deleteChat(authStatus, chatID)
This ensures we're not trying to save and delete the same chat data simultaneously. Simply changing the order of operations (dispose then delete) isn't enough to prevent the race condition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks!
@@ -34,3 +34,41 @@ test.extend<ExpectedV2Events>({ | |||
await expect(newHistoryItem).toBeVisible() | |||
await newHistoryItem.click() | |||
}) | |||
|
|||
test.extend<ExpectedV2Events>({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice!
Linear Issue
Problem
Previously, whenever a user deleted a chat, disposeChat would call clearAndRestartSession(), which in turn triggered saveSession(). This saved the just-deleted chat back into local storage, negating the deletion.
Solution
Introduce a skipSave boolean to conditionally skip the clearAndRestartSession() flow during deletion. If skipSave is true (e.g., for a deletion), clearAndRestartSession() is not called. This prevents the race condition of re-saving an already-deleted chat.
Why It Works
Using the skipSave flag to conditionally skip clearAndRestartSession() is safe because:
During normal operations (when skipSave is false), you want to clear and restart the session to maintain a clean state
During deletion (when skipSave is true), you want to skip this step because:
The chat is being deleted anyway
clearAndRestartSession() includes a saveSession() call which could race with the deletion
There's no need to create a new session when we're removing the chat
The condition helps prevent potential issues where:
So yes, using the skipSave flag to conditionally skip clearAndRestartSession() during deletion is a good practice for maintaining data consistency.
Test plan
Run this code in Vscode/Jetbrains debugger and delete a chat from history
Changelog