mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 23:28:27 +00:00
refactor: unify discord listener slow-log flow and test helpers
This commit is contained in:
@@ -67,38 +67,51 @@ describe("registerDiscordListener", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("DiscordMessageListener", () => {
|
describe("DiscordMessageListener", () => {
|
||||||
|
function createDeferred() {
|
||||||
|
let resolve: (() => void) | null = null;
|
||||||
|
const promise = new Promise<void>((done) => {
|
||||||
|
resolve = done;
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
promise,
|
||||||
|
resolve: () => {
|
||||||
|
if (typeof resolve === "function") {
|
||||||
|
(resolve as () => void)();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function expectPending(promise: Promise<unknown>) {
|
||||||
|
let resolved = false;
|
||||||
|
void promise.then(() => {
|
||||||
|
resolved = true;
|
||||||
|
});
|
||||||
|
await Promise.resolve();
|
||||||
|
expect(resolved).toBe(false);
|
||||||
|
}
|
||||||
|
|
||||||
it("awaits the handler before returning", async () => {
|
it("awaits the handler before returning", async () => {
|
||||||
let handlerResolved = false;
|
let handlerResolved = false;
|
||||||
let resolveHandler: (() => void) | null = null;
|
const deferred = createDeferred();
|
||||||
const handlerPromise = new Promise<void>((resolve) => {
|
const handler = vi.fn(async () => {
|
||||||
resolveHandler = () => {
|
await deferred.promise;
|
||||||
handlerResolved = true;
|
handlerResolved = true;
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
const handler = vi.fn(() => handlerPromise);
|
|
||||||
const listener = new DiscordMessageListener(handler);
|
const listener = new DiscordMessageListener(handler);
|
||||||
|
|
||||||
const handlePromise = listener.handle(
|
const handlePromise = listener.handle(
|
||||||
{} as unknown as import("./monitor/listeners.js").DiscordMessageEvent,
|
{} as unknown as import("./monitor/listeners.js").DiscordMessageEvent,
|
||||||
{} as unknown as import("@buape/carbon").Client,
|
{} as unknown as import("@buape/carbon").Client,
|
||||||
);
|
);
|
||||||
let handleResolved = false;
|
|
||||||
void handlePromise.then(() => {
|
|
||||||
handleResolved = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handler should be called but not yet resolved
|
// Handler should be called but not yet resolved
|
||||||
expect(handler).toHaveBeenCalledOnce();
|
expect(handler).toHaveBeenCalledOnce();
|
||||||
expect(handlerResolved).toBe(false);
|
expect(handlerResolved).toBe(false);
|
||||||
await Promise.resolve();
|
await expectPending(handlePromise);
|
||||||
expect(handleResolved).toBe(false);
|
|
||||||
|
|
||||||
// Release the handler
|
// Release the handler
|
||||||
const release = resolveHandler;
|
deferred.resolve();
|
||||||
if (typeof release === "function") {
|
|
||||||
(release as () => void)();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now await handle() - it should complete only after handler resolves
|
// Now await handle() - it should complete only after handler resolves
|
||||||
await handlePromise;
|
await handlePromise;
|
||||||
@@ -129,11 +142,8 @@ describe("DiscordMessageListener", () => {
|
|||||||
vi.setSystemTime(0);
|
vi.setSystemTime(0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let resolveHandler: (() => void) | null = null;
|
const deferred = createDeferred();
|
||||||
const handlerPromise = new Promise<void>((resolve) => {
|
const handler = vi.fn(() => deferred.promise);
|
||||||
resolveHandler = resolve;
|
|
||||||
});
|
|
||||||
const handler = vi.fn(() => handlerPromise);
|
|
||||||
const logger = {
|
const logger = {
|
||||||
warn: vi.fn(),
|
warn: vi.fn(),
|
||||||
error: vi.fn(),
|
error: vi.fn(),
|
||||||
@@ -145,21 +155,13 @@ describe("DiscordMessageListener", () => {
|
|||||||
{} as unknown as import("./monitor/listeners.js").DiscordMessageEvent,
|
{} as unknown as import("./monitor/listeners.js").DiscordMessageEvent,
|
||||||
{} as unknown as import("@buape/carbon").Client,
|
{} as unknown as import("@buape/carbon").Client,
|
||||||
);
|
);
|
||||||
let handleResolved = false;
|
await expectPending(handlePromise);
|
||||||
void handlePromise.then(() => {
|
|
||||||
handleResolved = true;
|
|
||||||
});
|
|
||||||
await Promise.resolve();
|
|
||||||
expect(handleResolved).toBe(false);
|
|
||||||
|
|
||||||
// Advance time past the slow listener threshold
|
// Advance time past the slow listener threshold
|
||||||
vi.setSystemTime(31_000);
|
vi.setSystemTime(31_000);
|
||||||
|
|
||||||
// Release the handler
|
// Release the handler
|
||||||
const release = resolveHandler;
|
deferred.resolve();
|
||||||
if (typeof release === "function") {
|
|
||||||
(release as () => void)();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now await handle() - it should complete and log the slow listener
|
// Now await handle() - it should complete and log the slow listener
|
||||||
await handlePromise;
|
await handlePromise;
|
||||||
|
|||||||
@@ -68,6 +68,32 @@ function logSlowDiscordListener(params: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function runDiscordListenerWithSlowLog(params: {
|
||||||
|
logger: Logger | undefined;
|
||||||
|
listener: string;
|
||||||
|
event: string;
|
||||||
|
run: () => Promise<void>;
|
||||||
|
onError?: (err: unknown) => void;
|
||||||
|
}) {
|
||||||
|
const startedAt = Date.now();
|
||||||
|
try {
|
||||||
|
await params.run();
|
||||||
|
} catch (err) {
|
||||||
|
if (params.onError) {
|
||||||
|
params.onError(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
logSlowDiscordListener({
|
||||||
|
logger: params.logger,
|
||||||
|
listener: params.listener,
|
||||||
|
event: params.event,
|
||||||
|
durationMs: Date.now() - startedAt,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function registerDiscordListener(listeners: Array<object>, listener: object) {
|
export function registerDiscordListener(listeners: Array<object>, listener: object) {
|
||||||
if (listeners.some((existing) => existing.constructor === listener.constructor)) {
|
if (listeners.some((existing) => existing.constructor === listener.constructor)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -85,19 +111,15 @@ export class DiscordMessageListener extends MessageCreateListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async handle(data: DiscordMessageEvent, client: Client) {
|
async handle(data: DiscordMessageEvent, client: Client) {
|
||||||
const startedAt = Date.now();
|
await runDiscordListenerWithSlowLog({
|
||||||
await this.handler(data, client)
|
|
||||||
.catch((err) => {
|
|
||||||
const logger = this.logger ?? discordEventQueueLog;
|
|
||||||
logger.error(danger(`discord handler failed: ${String(err)}`));
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
logSlowDiscordListener({
|
|
||||||
logger: this.logger,
|
logger: this.logger,
|
||||||
listener: this.constructor.name,
|
listener: this.constructor.name,
|
||||||
event: this.type,
|
event: this.type,
|
||||||
durationMs: Date.now() - startedAt,
|
run: () => this.handler(data, client),
|
||||||
});
|
onError: (err) => {
|
||||||
|
const logger = this.logger ?? discordEventQueueLog;
|
||||||
|
logger.error(danger(`discord handler failed: ${String(err)}`));
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,9 +166,12 @@ async function runDiscordReactionHandler(params: {
|
|||||||
listener: string;
|
listener: string;
|
||||||
event: string;
|
event: string;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const startedAt = Date.now();
|
await runDiscordListenerWithSlowLog({
|
||||||
try {
|
logger: params.handlerParams.logger,
|
||||||
await handleDiscordReactionEvent({
|
listener: params.listener,
|
||||||
|
event: params.event,
|
||||||
|
run: () =>
|
||||||
|
handleDiscordReactionEvent({
|
||||||
data: params.data,
|
data: params.data,
|
||||||
client: params.client,
|
client: params.client,
|
||||||
action: params.action,
|
action: params.action,
|
||||||
@@ -155,15 +180,8 @@ async function runDiscordReactionHandler(params: {
|
|||||||
botUserId: params.handlerParams.botUserId,
|
botUserId: params.handlerParams.botUserId,
|
||||||
guildEntries: params.handlerParams.guildEntries,
|
guildEntries: params.handlerParams.guildEntries,
|
||||||
logger: params.handlerParams.logger,
|
logger: params.handlerParams.logger,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
} finally {
|
|
||||||
logSlowDiscordListener({
|
|
||||||
logger: params.handlerParams.logger,
|
|
||||||
listener: params.listener,
|
|
||||||
event: params.event,
|
|
||||||
durationMs: Date.now() - startedAt,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleDiscordReactionEvent(params: {
|
async function handleDiscordReactionEvent(params: {
|
||||||
|
|||||||
Reference in New Issue
Block a user