mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 18:00:54 +00:00
Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -200,7 +200,9 @@ export function createProfileAvailability({
|
||||
throw new BrowserProfileUnavailableError(formatChromeMcpAttachFailure(lastError));
|
||||
};
|
||||
|
||||
const ensureBrowserAvailable = async (): Promise<void> => {
|
||||
let inflightEnsureBrowserAvailable: Promise<void> | null = null;
|
||||
|
||||
const ensureBrowserAvailableOnce = async (): Promise<void> => {
|
||||
await reconcileProfileRuntime();
|
||||
if (capabilities.usesChromeMcp) {
|
||||
if (profile.userDataDir && !fs.existsSync(profile.userDataDir)) {
|
||||
@@ -305,6 +307,16 @@ export function createProfileAvailability({
|
||||
}
|
||||
};
|
||||
|
||||
const ensureBrowserAvailable = async (): Promise<void> => {
|
||||
if (inflightEnsureBrowserAvailable) {
|
||||
return inflightEnsureBrowserAvailable;
|
||||
}
|
||||
inflightEnsureBrowserAvailable = ensureBrowserAvailableOnce().finally(() => {
|
||||
inflightEnsureBrowserAvailable = null;
|
||||
});
|
||||
return inflightEnsureBrowserAvailable;
|
||||
};
|
||||
|
||||
const stopRunningBrowser = async (): Promise<{ stopped: boolean }> => {
|
||||
await reconcileProfileRuntime();
|
||||
if (capabilities.usesChromeMcp) {
|
||||
|
||||
@@ -88,6 +88,42 @@ describe("browser server-context ensureBrowserAvailable", () => {
|
||||
expect(stopOpenClawChrome).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("deduplicates concurrent lazy-start calls to prevent PortInUseError", async () => {
|
||||
const { launchOpenClawChrome, stopOpenClawChrome, isChromeCdpReady, profile } =
|
||||
setupEnsureBrowserAvailableHarness();
|
||||
isChromeCdpReady.mockResolvedValue(true);
|
||||
mockLaunchedChrome(launchOpenClawChrome, 456);
|
||||
|
||||
const first = profile.ensureBrowserAvailable();
|
||||
const second = profile.ensureBrowserAvailable();
|
||||
await vi.advanceTimersByTimeAsync(100);
|
||||
await expect(Promise.all([first, second])).resolves.toEqual([undefined, undefined]);
|
||||
|
||||
expect(launchOpenClawChrome).toHaveBeenCalledTimes(1);
|
||||
expect(stopOpenClawChrome).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("clears the concurrent lazy-start guard after launch failure", async () => {
|
||||
const { launchOpenClawChrome, stopOpenClawChrome, isChromeCdpReady, profile } =
|
||||
setupEnsureBrowserAvailableHarness();
|
||||
isChromeCdpReady.mockResolvedValue(true);
|
||||
launchOpenClawChrome.mockRejectedValueOnce(
|
||||
new Error("PortInUseError: listen EADDRINUSE 127.0.0.1:18800"),
|
||||
);
|
||||
|
||||
const first = profile.ensureBrowserAvailable();
|
||||
const second = profile.ensureBrowserAvailable();
|
||||
await expect(Promise.all([first, second])).rejects.toThrow("PortInUseError");
|
||||
|
||||
mockLaunchedChrome(launchOpenClawChrome, 789);
|
||||
const retry = profile.ensureBrowserAvailable();
|
||||
await vi.advanceTimersByTimeAsync(100);
|
||||
await expect(retry).resolves.toBeUndefined();
|
||||
|
||||
expect(launchOpenClawChrome).toHaveBeenCalledTimes(2);
|
||||
expect(stopOpenClawChrome).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reuses a pre-existing loopback browser after an initial short probe miss", async () => {
|
||||
const { launchOpenClawChrome, stopOpenClawChrome, isChromeCdpReady, profile, state } =
|
||||
setupEnsureBrowserAvailableHarness();
|
||||
|
||||
Reference in New Issue
Block a user