fix(discord): require real gateway readiness

This commit is contained in:
Peter Steinberger
2026-04-24 18:16:54 +01:00
parent a08a2e381f
commit 78a431ed22
3 changed files with 44 additions and 11 deletions

View File

@@ -101,17 +101,19 @@ describe("runDiscordGatewayLifecycle", () => {
}
function createLifecycleHarness(params?: {
gateway?: MockGateway;
gateway?: MockGateway | null;
isDisallowedIntentsError?: (err: unknown) => boolean;
pendingGatewayEvents?: DiscordGatewayEvent[];
}) {
const gateway =
params?.gateway ??
(() => {
const defaultGateway = createGatewayHarness().gateway;
defaultGateway.isConnected = true;
return defaultGateway;
})();
params && "gateway" in params
? params.gateway
: (() => {
const defaultGateway = createGatewayHarness().gateway;
defaultGateway.isConnected = true;
return defaultGateway;
})();
const gatewayEmitter = gateway?.emitter ?? new EventEmitter();
const threadStop = vi.fn();
const runtimeLog = vi.fn();
const runtimeError = vi.fn();
@@ -130,7 +132,7 @@ describe("runDiscordGatewayLifecycle", () => {
return "continue";
}),
dispose: vi.fn(),
emitter: gateway.emitter,
emitter: gatewayEmitter,
};
const statusSink = vi.fn();
const runtime: RuntimeEnv = {
@@ -146,7 +148,7 @@ describe("runDiscordGatewayLifecycle", () => {
statusSink,
lifecycleParams: {
accountId: "default",
gateway: gateway as unknown as MutableDiscordGateway,
gateway: gateway ? (gateway as unknown as MutableDiscordGateway) : undefined,
runtime,
isDisallowedIntentsError: params?.isDisallowedIntentsError ?? (() => false),
voiceManager: null,
@@ -215,6 +217,38 @@ describe("runDiscordGatewayLifecycle", () => {
);
});
it("does not treat a missing gateway handle as ready", async () => {
vi.useFakeTimers();
try {
const { lifecycleParams, threadStop, statusSink, gatewaySupervisor } = createLifecycleHarness(
{
gateway: null,
},
);
const lifecyclePromise = runDiscordGatewayLifecycle(lifecycleParams);
lifecyclePromise.catch(() => {});
await vi.advanceTimersByTimeAsync(0);
await vi.advanceTimersByTimeAsync(15_500);
await expect(lifecyclePromise).rejects.toThrow(
"discord gateway did not reach READY within 15000ms",
);
expect(statusSink).not.toHaveBeenCalledWith(
expect.objectContaining({
connected: true,
}),
);
expectLifecycleCleanup({
threadStop,
waitCalls: 0,
gatewaySupervisor,
});
} finally {
vi.useRealTimers();
}
});
it("restarts the gateway once when startup never reaches READY, then recovers", async () => {
vi.useFakeTimers();
try {

View File

@@ -287,7 +287,7 @@ async function waitForGatewayReady(params: {
if ((await params.beforePoll?.()) === "stop") {
return "stopped";
}
if (params.gateway?.isConnected ?? true) {
if (params.gateway?.isConnected === true) {
const at = Date.now();
params.pushStatus?.({
...createConnectedChannelStatusPatch(at),

View File

@@ -1,6 +1,5 @@
import type { StreamFn } from "@mariozechner/pi-agent-core";
import { diagnosticErrorCategory } from "../../../infra/diagnostic-error-metadata.js";
export { diagnosticErrorCategory } from "../../../infra/diagnostic-error-metadata.js";
import {
emitDiagnosticEvent,
type DiagnosticEventInput,