fix(session): 修复 getOrCreateProject 死锁问题
读写锁嵌套导致死锁:在持有读锁的情况下尝试获取写锁。 改为先释放读锁再获取写锁,并使用双重检查模式防止竞态条件。
This commit is contained in:
@@ -83,29 +83,42 @@ export class SessionStorage {
|
||||
const projectId = await getProjectId(workdir);
|
||||
const projectFile = path.join(this.projectDir, `${projectId}.json`);
|
||||
|
||||
using _ = await Lock.read(projectFile);
|
||||
// 先尝试读取(只需读锁)
|
||||
{
|
||||
using _ = await Lock.read(projectFile);
|
||||
try {
|
||||
const content = await fs.readFile(projectFile, 'utf-8');
|
||||
return JSON.parse(content) as ProjectMetadata;
|
||||
} catch {
|
||||
// 项目不存在,需要创建
|
||||
}
|
||||
}
|
||||
|
||||
// 读锁已释放,获取写锁来创建项目
|
||||
using _ = await Lock.write(projectFile);
|
||||
|
||||
// 双重检查:可能其他进程已经创建了
|
||||
try {
|
||||
const content = await fs.readFile(projectFile, 'utf-8');
|
||||
return JSON.parse(content) as ProjectMetadata;
|
||||
} catch {
|
||||
// 项目不存在,创建新项目
|
||||
const isGitRepo = await isGitRepository(workdir);
|
||||
const project: ProjectMetadata = {
|
||||
id: projectId,
|
||||
workdir,
|
||||
createdAt: new Date().toISOString(),
|
||||
isGitRepo,
|
||||
};
|
||||
|
||||
using __ = await Lock.write(projectFile);
|
||||
await fs.writeFile(projectFile, JSON.stringify(project, null, 2), 'utf-8');
|
||||
|
||||
// 确保项目的会话目录存在
|
||||
await fs.mkdir(path.join(this.sessionDir, projectId), { recursive: true });
|
||||
|
||||
return project;
|
||||
// 确实不存在,创建新项目
|
||||
}
|
||||
|
||||
const isGitRepo = await isGitRepository(workdir);
|
||||
const project: ProjectMetadata = {
|
||||
id: projectId,
|
||||
workdir,
|
||||
createdAt: new Date().toISOString(),
|
||||
isGitRepo,
|
||||
};
|
||||
|
||||
await fs.writeFile(projectFile, JSON.stringify(project, null, 2), 'utf-8');
|
||||
|
||||
// 确保项目的会话目录存在
|
||||
await fs.mkdir(path.join(this.sessionDir, projectId), { recursive: true });
|
||||
|
||||
return project;
|
||||
}
|
||||
|
||||
// ========== 会话元数据管理 ==========
|
||||
|
||||
Reference in New Issue
Block a user