fix(mutex): prioritize waiting exclusive locks over newly added shared tasks
This commit is contained in:
parent
cbc9da0e26
commit
1047f54523
2 changed files with 42 additions and 2 deletions
38
app/server/core/__tests__/repository-mutex.test.ts
Normal file
38
app/server/core/__tests__/repository-mutex.test.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { test, describe, expect } from "bun:test";
|
||||
import { repoMutex } from "../repository-mutex";
|
||||
|
||||
describe("RepositoryMutex", () => {
|
||||
test("should prioritize waiting exclusive locks over new shared locks", async () => {
|
||||
const repoId = "test-repo";
|
||||
const results: string[] = [];
|
||||
|
||||
const releaseShared1 = await repoMutex.acquireShared(repoId, "backup-1");
|
||||
results.push("acquired-shared-1");
|
||||
|
||||
const exclusivePromise = repoMutex.acquireExclusive(repoId, "unlock").then((release) => {
|
||||
results.push("acquired-exclusive");
|
||||
return release;
|
||||
});
|
||||
|
||||
const shared2Promise = repoMutex.acquireShared(repoId, "backup-2").then((release) => {
|
||||
results.push("acquired-shared-2");
|
||||
return release;
|
||||
});
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
|
||||
expect(results).toEqual(["acquired-shared-1"]);
|
||||
|
||||
releaseShared1();
|
||||
|
||||
const releaseExclusive = await exclusivePromise;
|
||||
expect(results).toEqual(["acquired-shared-1", "acquired-exclusive"]);
|
||||
|
||||
releaseExclusive();
|
||||
|
||||
const releaseShared2 = await shared2Promise;
|
||||
expect(results).toEqual(["acquired-shared-1", "acquired-exclusive", "acquired-shared-2"]);
|
||||
|
||||
releaseShared2();
|
||||
});
|
||||
});
|
||||
|
|
@ -49,7 +49,9 @@ class RepositoryMutex {
|
|||
async acquireShared(repositoryId: string, operation: string): Promise<() => void> {
|
||||
const state = this.getOrCreateState(repositoryId);
|
||||
|
||||
if (!state.exclusiveHolder) {
|
||||
const hasExclusiveInQueue = state.waitQueue.some((item) => item.type === "exclusive");
|
||||
|
||||
if (!state.exclusiveHolder && !hasExclusiveInQueue) {
|
||||
const lockId = this.generateLockId();
|
||||
state.sharedHolders.set(lockId, {
|
||||
id: lockId,
|
||||
|
|
@ -60,7 +62,7 @@ class RepositoryMutex {
|
|||
}
|
||||
|
||||
logger.debug(
|
||||
`[Mutex] Waiting for shared lock on repo ${repositoryId}: ${operation} (exclusive held by: ${state.exclusiveHolder.operation})`,
|
||||
`[Mutex] Waiting for shared lock on repo ${repositoryId}: ${operation} (exclusive held by: ${state.exclusiveHolder?.operation ?? "none"}, queue: ${state.waitQueue.length})`,
|
||||
);
|
||||
const lockId = await new Promise<string>((resolve) => {
|
||||
state.waitQueue.push({ type: "shared", operation, resolve });
|
||||
|
|
|
|||
Loading…
Reference in a new issue