fix: limit restored terminal reconnects
This commit is contained in:
parent
a139a6c2ad
commit
95c0fdf71e
|
|
@ -300,6 +300,35 @@ describe("useTerminalSession", () => {
|
|||
expect(muxes[1].inputs).toEqual([["handle-1", "echo ok\r"]]);
|
||||
});
|
||||
|
||||
it("does not reconnect a broken live pane on ordinary session updates", () => {
|
||||
const muxes: FakeMux[] = [];
|
||||
const createMux = () => {
|
||||
const fake = createFakeMux();
|
||||
muxes.push(fake);
|
||||
return fake.mux;
|
||||
};
|
||||
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
const wrapper = ({ children }: { children: ReactNode }) => (
|
||||
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
);
|
||||
const view = renderHook(
|
||||
({ attachedSession }) => useTerminalSession(attachedSession, { daemonReady: true, createMux }),
|
||||
{ initialProps: { attachedSession: session }, wrapper },
|
||||
);
|
||||
const terminal = createFakeTerminal();
|
||||
act(() => {
|
||||
view.result.current.attach(terminal);
|
||||
});
|
||||
act(() => muxes[0].emitError("handle-1", "no such pane"));
|
||||
expect(view.result.current.state).toBe("error");
|
||||
|
||||
view.rerender({ attachedSession: { ...session, status: "idle", updatedAt: "tick-1" } });
|
||||
view.rerender({ attachedSession: { ...session, status: "working", updatedAt: "tick-2" } });
|
||||
|
||||
expect(view.result.current.state).toBe("error");
|
||||
expect(muxes).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("surfaces pane errors and refetches, with no automatic retry", () => {
|
||||
const { view, muxes, invalidateSpy } = setup();
|
||||
act(() => muxes[0].emitError("handle-1", "no such pane"));
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ export function useTerminalSession(session: WorkspaceSession | undefined, option
|
|||
|
||||
const sessionRef = useRef(session);
|
||||
sessionRef.current = session;
|
||||
const previousSessionStatusRef = useRef(session?.status);
|
||||
const optionsRef = useRef(options);
|
||||
optionsRef.current = options;
|
||||
const stateRef = useRef<TerminalSessionState>(state);
|
||||
|
|
@ -326,7 +327,17 @@ export function useTerminalSession(session: WorkspaceSession | undefined, option
|
|||
useEffect(() => {
|
||||
const r = runtime.current;
|
||||
const handle = session?.terminalHandleId ?? null;
|
||||
if (!handle || session?.status === "terminated" || r.detached || !r.terminal) return;
|
||||
const previousStatus = previousSessionStatusRef.current;
|
||||
previousSessionStatusRef.current = session?.status;
|
||||
if (
|
||||
!handle ||
|
||||
previousStatus !== "terminated" ||
|
||||
session?.status === "terminated" ||
|
||||
r.detached ||
|
||||
!r.terminal
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (r.handle !== handle) return;
|
||||
if (stateRef.current !== "exited" && stateRef.current !== "error") return;
|
||||
if (optionsRef.current.daemonReady) {
|
||||
|
|
@ -335,7 +346,7 @@ export function useTerminalSession(session: WorkspaceSession | undefined, option
|
|||
} else {
|
||||
transition("reattaching");
|
||||
}
|
||||
}, [connect, session?.status, session?.terminalHandleId, session?.updatedAt, transition]);
|
||||
}, [connect, session?.status, session?.terminalHandleId, transition]);
|
||||
|
||||
// Belt-and-braces: never leak a socket past unmount, even if the owner
|
||||
// forgot to call detach.
|
||||
|
|
|
|||
Loading…
Reference in New Issue