fix(discord): harden Carbon parity

This commit is contained in:
clawsweeper
2026-05-02 11:11:17 +00:00
parent 3aef19e104
commit 3895f20141
3 changed files with 59 additions and 11 deletions

View File

@@ -433,6 +433,9 @@ export class RestScheduler<TData> {
lane: RequestPriority,
now: number,
): void {
if (lane !== "background") {
return;
}
const staleAfterMs = this.options.lanes[lane].staleAfterMs;
if (!staleAfterMs || staleAfterMs <= 0) {
return;

View File

@@ -111,6 +111,60 @@ describe("RequestClient", () => {
);
});
it("keeps standard mutations queued until Discord accepts or rejects them", async () => {
vi.useFakeTimers();
vi.setSystemTime(0);
const firstResponse = createDeferred<Response>();
const fetchSpy = vi.fn(async () =>
fetchSpy.mock.calls.length === 1
? await firstResponse.promise
: createJsonResponse({ ok: true }),
);
const client = new RequestClient("test-token", {
fetch: fetchSpy,
scheduler: {
maxConcurrency: 1,
lanes: {
background: { staleAfterMs: 50 },
standard: { staleAfterMs: 50 },
},
},
});
const requests = [
client.post("/channels/c1/messages", { body: { content: "send" } }),
client.patch("/channels/c1/messages/m1", { body: { content: "edit" } }),
client.delete("/channels/c1/messages/m2"),
client.post("/webhooks/app/token", { body: { content: "webhook send" } }),
client.patch("/webhooks/app/token/messages/@original", {
body: { content: "webhook edit" },
}),
client.delete("/webhooks/app/token/messages/@original"),
client.post("/applications/app/commands", { body: { name: "ping" } }),
];
await vi.waitFor(() => expect(fetchSpy).toHaveBeenCalledTimes(1));
await vi.advanceTimersByTimeAsync(51);
firstResponse.resolve(createJsonResponse({ ok: true }));
await expect(Promise.all(requests)).resolves.toEqual([
{ ok: true },
{ ok: true },
{ ok: true },
{ ok: true },
{ ok: true },
{ ok: true },
{ ok: true },
]);
expect(fetchSpy).toHaveBeenCalledTimes(requests.length);
expect(client.getSchedulerMetrics()).toEqual(
expect.objectContaining({
droppedByLane: expect.objectContaining({ standard: 0 }),
queueSize: 0,
}),
);
});
it("runs independent route buckets concurrently", async () => {
const channelResponse = createDeferred<Response>();
const guildResponse = createDeferred<Response>();

View File

@@ -72,7 +72,7 @@ const defaultOptions = {
const DEFAULT_MAX_CONCURRENT_WORKERS = 4;
const defaultLaneOptions: Record<RestRequestPriority, { staleAfterMs?: number; weight: number }> = {
critical: { weight: 6 },
standard: { staleAfterMs: 60_000, weight: 3 },
standard: { weight: 3 },
background: { staleAfterMs: 20_000, weight: 1 },
};
@@ -318,14 +318,5 @@ function getRequestPriority(method: string, path: string): RestRequestPriority {
if (/^\/interactions\/\d+\/[^/]+\/callback$/.test(normalizedPath)) {
return "critical";
}
if (
normalizedPath.startsWith("/webhooks/") &&
(normalizedMethod === "POST" || normalizedMethod === "PATCH" || normalizedMethod === "DELETE")
) {
return "standard";
}
if (normalizedMethod !== "GET" && /\/channels\/\d+\/messages/.test(normalizedPath)) {
return "standard";
}
return "background";
return normalizedMethod === "GET" ? "background" : "standard";
}