Skip to content

Commit 16e89f4

Browse files
committed
Added some more run lock tests
1 parent 11e1cfc commit 16e89f4

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

internal-packages/run-engine/src/engine/tests/locking.test.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,121 @@ describe("RunLocker", () => {
9999
}
100100
}
101101
);
102+
103+
redisTest("Test lock throws when it times out", { timeout: 15_000 }, async ({ redisOptions }) => {
104+
const redis = createRedisClient(redisOptions);
105+
try {
106+
const runLock = new RunLocker({ redis });
107+
108+
// First, ensure we can acquire the lock normally
109+
let firstLockAcquired = false;
110+
await runLock.lock(["test-1"], 5000, async () => {
111+
firstLockAcquired = true;
112+
});
113+
//wait for 20ms
114+
await new Promise((resolve) => setTimeout(resolve, 20));
115+
116+
expect(firstLockAcquired).toBe(true);
117+
118+
// Now create a long-running lock
119+
const lockPromise1 = runLock.lock(["test-1"], 5000, async () => {
120+
// Hold the lock longer than all possible retry attempts
121+
// (10 retries * (200ms delay + 200ms max jitter) = ~4000ms max)
122+
await new Promise((resolve) => setTimeout(resolve, 5000));
123+
});
124+
125+
// Try to acquire same lock immediately
126+
await expect(
127+
runLock.lock(["test-1"], 5000, async () => {
128+
// This should never execute
129+
expect(true).toBe(false);
130+
})
131+
).rejects.toThrow("unable to achieve a quorum");
132+
133+
// Complete the first lock
134+
await lockPromise1;
135+
136+
// Verify final state
137+
expect(runLock.isInsideLock()).toBe(false);
138+
} finally {
139+
await redis.quit();
140+
}
141+
});
142+
143+
redisTest(
144+
"Test nested lock with same resources doesn't timeout",
145+
{ timeout: 15_000 },
146+
async ({ redisOptions }) => {
147+
const redis = createRedisClient(redisOptions);
148+
try {
149+
const runLock = new RunLocker({ redis });
150+
151+
await runLock.lock(["test-1"], 5000, async () => {
152+
// First lock acquired
153+
expect(runLock.isInsideLock()).toBe(true);
154+
155+
// Try to acquire the same resource with a very short timeout
156+
// This should work because we already hold the lock
157+
await runLock.lock(["test-1"], 100, async () => {
158+
expect(runLock.isInsideLock()).toBe(true);
159+
// Wait longer than the timeout to prove it doesn't matter
160+
await new Promise((resolve) => setTimeout(resolve, 500));
161+
});
162+
});
163+
164+
// Verify final state
165+
expect(runLock.isInsideLock()).toBe(false);
166+
} finally {
167+
await redis.quit();
168+
}
169+
}
170+
);
171+
172+
redisTest(
173+
"Test nested lock with same resource works regardless of retries",
174+
{ timeout: 15_000 },
175+
async ({ redisOptions }) => {
176+
const redis = createRedisClient(redisOptions);
177+
try {
178+
const runLock = new RunLocker({ redis });
179+
180+
// First verify we can acquire the lock normally
181+
let firstLockAcquired = false;
182+
await runLock.lock(["test-1"], 5000, async () => {
183+
firstLockAcquired = true;
184+
});
185+
expect(firstLockAcquired).toBe(true);
186+
187+
// Now test the nested lock behavior
188+
let outerLockExecuted = false;
189+
let innerLockExecuted = false;
190+
191+
await runLock.lock(["test-1"], 5000, async () => {
192+
outerLockExecuted = true;
193+
expect(runLock.isInsideLock()).toBe(true);
194+
expect(runLock.getCurrentResources()).toBe("test-1");
195+
196+
// Try to acquire the same resource in a nested lock
197+
// This should work immediately without any retries
198+
// because we already hold the lock
199+
await runLock.lock(["test-1"], 5000, async () => {
200+
innerLockExecuted = true;
201+
expect(runLock.isInsideLock()).toBe(true);
202+
expect(runLock.getCurrentResources()).toBe("test-1");
203+
204+
// Sleep longer than retry attempts would take
205+
// (10 retries * (200ms delay + 200ms max jitter) = ~4000ms max)
206+
await new Promise((resolve) => setTimeout(resolve, 5000));
207+
});
208+
});
209+
210+
// Verify both locks executed
211+
expect(outerLockExecuted).toBe(true);
212+
expect(innerLockExecuted).toBe(true);
213+
expect(runLock.isInsideLock()).toBe(false);
214+
} finally {
215+
await redis.quit();
216+
}
217+
}
218+
);
102219
});

0 commit comments

Comments
 (0)