Skip to content

Commit 5b2e8ac

Browse files
fix(discord): surface stalled transport health
1 parent 8178d5d commit 5b2e8ac

2 files changed

Lines changed: 60 additions & 2 deletions

File tree

src/gateway/protocol/channels.schema.test.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import AjvPkg from "ajv";
22
import { describe, expect, it } from "vitest";
3-
import { WebLoginWaitParamsSchema } from "./schema/channels.js";
3+
import { ChannelsStatusResultSchema, WebLoginWaitParamsSchema } from "./schema/channels.js";
4+
5+
const Ajv = AjvPkg as unknown as new (opts?: object) => import("ajv").default;
46

57
describe("WebLoginWaitParamsSchema", () => {
6-
const Ajv = AjvPkg as unknown as new (opts?: object) => import("ajv").default;
78
const validate = new Ajv().compile(WebLoginWaitParamsSchema);
89

910
it("bounds caller-provided QR data URLs", () => {
@@ -25,3 +26,40 @@ describe("WebLoginWaitParamsSchema", () => {
2526
).toBe(false);
2627
});
2728
});
29+
30+
describe("ChannelsStatusResultSchema", () => {
31+
const validate = new Ajv().compile(ChannelsStatusResultSchema);
32+
33+
it("accepts gateway event-loop diagnostics emitted by channels.status", () => {
34+
expect(
35+
validate({
36+
ts: Date.now(),
37+
channelOrder: ["discord"],
38+
channelLabels: { discord: "Discord" },
39+
channels: { discord: { configured: true } },
40+
channelAccounts: {
41+
discord: [
42+
{
43+
accountId: "default",
44+
enabled: true,
45+
configured: true,
46+
running: true,
47+
connected: false,
48+
healthState: "stale-socket",
49+
},
50+
],
51+
},
52+
channelDefaultAccountId: { discord: "default" },
53+
eventLoop: {
54+
degraded: true,
55+
reasons: ["event_loop_delay", "cpu"],
56+
intervalMs: 62_000,
57+
delayP99Ms: 1_250.5,
58+
delayMaxMs: 62_000,
59+
utilization: 0.98,
60+
cpuCoreRatio: 1.2,
61+
},
62+
}),
63+
).toBe(true);
64+
});
65+
});

src/gateway/protocol/schema/channels.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,25 @@ export const ChannelUiMetaSchema = Type.Object(
287287
{ additionalProperties: false },
288288
);
289289

290+
export const ChannelEventLoopHealthSchema = Type.Object(
291+
{
292+
degraded: Type.Boolean(),
293+
reasons: Type.Array(
294+
Type.Union([
295+
Type.Literal("event_loop_delay"),
296+
Type.Literal("event_loop_utilization"),
297+
Type.Literal("cpu"),
298+
]),
299+
),
300+
intervalMs: Type.Integer({ minimum: 0 }),
301+
delayP99Ms: Type.Number({ minimum: 0 }),
302+
delayMaxMs: Type.Number({ minimum: 0 }),
303+
utilization: Type.Number({ minimum: 0 }),
304+
cpuCoreRatio: Type.Number({ minimum: 0 }),
305+
},
306+
{ additionalProperties: false },
307+
);
308+
290309
export const ChannelsStatusResultSchema = Type.Object(
291310
{
292311
ts: Type.Integer({ minimum: 0 }),
@@ -298,6 +317,7 @@ export const ChannelsStatusResultSchema = Type.Object(
298317
channels: Type.Record(NonEmptyString, Type.Unknown()),
299318
channelAccounts: Type.Record(NonEmptyString, Type.Array(ChannelAccountSnapshotSchema)),
300319
channelDefaultAccountId: Type.Record(NonEmptyString, NonEmptyString),
320+
eventLoop: Type.Optional(ChannelEventLoopHealthSchema),
301321
},
302322
{ additionalProperties: false },
303323
);

0 commit comments

Comments
 (0)