Replies were locked per bot, so a long reply in one session held up every other session's reply with nothing shown. The lock is now per session. A chat shows the thinking row whenever the user has the last word, rather than from the bot's face (one per user, shared by every session), so it shows even while the bot works elsewhere. A task waiting for its busy computer says so, and a job finishing while another still runs puts back the running one's face. Co-Authored-By: Claude Opus 5.5 <[email protected]>
84 lines
2.4 KiB
TypeScript
84 lines
2.4 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import createKeyLock from "./create-key-lock";
|
|
|
|
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
|
describe("createKeyLock", () => {
|
|
test("runs tasks with the same key one at a time, in order", async () => {
|
|
const lock = createKeyLock();
|
|
const events: string[] = [];
|
|
|
|
const job = (name: string, ms: number) =>
|
|
lock.run({
|
|
key: 1,
|
|
task: async () => {
|
|
events.push(`${name}:start`);
|
|
await wait(ms);
|
|
events.push(`${name}:end`);
|
|
return name;
|
|
},
|
|
});
|
|
|
|
const results = await Promise.all([job("a", 20), job("b", 1)]);
|
|
|
|
expect(results).toEqual(["a", "b"]);
|
|
expect(events).toEqual(["a:start", "a:end", "b:start", "b:end"]);
|
|
expect(lock.size()).toBe(0);
|
|
});
|
|
|
|
test("runs different keys side by side", async () => {
|
|
const lock = createKeyLock();
|
|
const events: string[] = [];
|
|
|
|
await Promise.all([
|
|
lock.run({
|
|
key: "x",
|
|
task: async () => {
|
|
events.push("x:start");
|
|
await wait(20);
|
|
events.push("x:end");
|
|
},
|
|
}),
|
|
lock.run({
|
|
key: "y",
|
|
task: async () => {
|
|
events.push("y:start");
|
|
events.push("y:end");
|
|
},
|
|
}),
|
|
]);
|
|
|
|
expect(events.indexOf("y:end")).toBeLessThan(events.indexOf("x:end"));
|
|
});
|
|
|
|
test("a failing task doesn't block the next one", async () => {
|
|
const lock = createKeyLock();
|
|
|
|
const failed = lock.run({
|
|
key: 1,
|
|
task: async () => {
|
|
throw new Error("boom");
|
|
},
|
|
});
|
|
const next = lock.run({ key: 1, task: async () => "ok" });
|
|
|
|
expect(failed).rejects.toThrow("boom");
|
|
expect(await next).toBe("ok");
|
|
});
|
|
|
|
test("is busy while a task with the key is running", async () => {
|
|
const lock = createKeyLock();
|
|
|
|
expect(lock.busy({ key: 1 })).toBe(false);
|
|
|
|
const running = lock.run({ key: 1, task: () => wait(10) });
|
|
|
|
expect(lock.busy({ key: 1 })).toBe(true);
|
|
expect(lock.busy({ key: 2 })).toBe(false);
|
|
|
|
await running;
|
|
|
|
expect(lock.busy({ key: 1 })).toBe(false);
|
|
});
|
|
});
|