diff --git a/.changeset/disconnect-after-run.md b/.changeset/disconnect-after-run.md new file mode 100644 index 0000000..06bb86c --- /dev/null +++ b/.changeset/disconnect-after-run.md @@ -0,0 +1,6 @@ +--- +"@e2b/desktop": patch +"@e2b/desktop-python": patch +--- + +Disconnect from fire-and-forget background commands. After background `commands.run` calls whose output is never read (`xdg-open`, `gtk-launch`, `Xvfb`, `startxfce4`), the SDK now calls `.disconnect()` so it stops holding the command's event stream open while the process keeps running. diff --git a/packages/js-sdk/src/sandbox.ts b/packages/js-sdk/src/sandbox.ts index 71ef691..9e2a135 100644 --- a/packages/js-sdk/src/sandbox.ts +++ b/packages/js-sdk/src/sandbox.ts @@ -467,9 +467,10 @@ export class Sandbox extends SandboxBase { * @param fileOrUrl - The file or URL to open. */ async open(fileOrUrl: string): Promise { - await this.commands.run(`xdg-open ${fileOrUrl}`, { + const handle = await this.commands.run(`xdg-open ${fileOrUrl}`, { background: true, }) + await handle.disconnect() } /** @@ -511,10 +512,14 @@ export class Sandbox extends SandboxBase { * @param uri - The URI to open in the application. */ async launch(application: string, uri?: string): Promise { - await this.commands.run(`gtk-launch ${application} ${uri ?? ''}`, { - background: true, - timeoutMs: 0, - }) + const handle = await this.commands.run( + `gtk-launch ${application} ${uri ?? ''}`, + { + background: true, + timeoutMs: 0, + } + ) + await handle.disconnect() } protected async _start(display: string, opts?: SandboxOpts): Promise { @@ -523,11 +528,12 @@ export class Sandbox extends SandboxBase { this.stream = new VNCServer(this) const [width, height] = opts?.resolution ?? [1024, 768] - await this.commands.run( + const xvfbHandle = await this.commands.run( `Xvfb ${display} -ac -screen 0 ${width}x${height}x24 ` + `-retro -dpi ${opts?.dpi ?? 96} -nolisten tcp -nolisten unix`, { background: true, timeoutMs: 0 } ) + await xvfbHandle.disconnect() const hasStarted = await this.waitAndVerify( `xdpyinfo -display ${display}`, @@ -559,6 +565,7 @@ export class Sandbox extends SandboxBase { timeoutMs: 0, }) this.lastXfce4Pid = result.pid + await result.disconnect() } } diff --git a/packages/python-sdk/e2b_desktop/main.py b/packages/python-sdk/e2b_desktop/main.py index 2077721..1cac91c 100644 --- a/packages/python-sdk/e2b_desktop/main.py +++ b/packages/python-sdk/e2b_desktop/main.py @@ -260,12 +260,13 @@ def create( sbx._display = display width, height = resolution or (1024, 768) - sbx.commands.run( + xvfb_handle = sbx.commands.run( f"Xvfb {display} -ac -screen 0 {width}x{height}x24" f" -retro -dpi {dpi or 96} -nolisten tcp -nolisten unix", background=True, timeout=0, ) + xvfb_handle.disconnect() if not sbx._wait_and_verify( f"xdpyinfo -display {display}", lambda r: r.exit_code == 0 @@ -306,9 +307,9 @@ def _start_xfce4(self): f"ps aux | grep {self._last_xfce4_pid} | grep -v grep | head -n 1" ).stdout.strip() ): - self._last_xfce4_pid = self.commands.run( - "startxfce4", background=True, timeout=0 - ).pid + xfce4_handle = self.commands.run("startxfce4", background=True, timeout=0) + self._last_xfce4_pid = xfce4_handle.pid + xfce4_handle.disconnect() @property def stream(self) -> _VNCServer: @@ -511,7 +512,8 @@ def open(self, file_or_url: str): :param file_or_url: The file or URL to open. """ - self.commands.run(f"xdg-open {file_or_url}", background=True) + handle = self.commands.run(f"xdg-open {file_or_url}", background=True) + handle.disconnect() def get_current_window_id(self) -> str: """ @@ -539,6 +541,7 @@ def launch(self, application: str, uri: Optional[str] = None): """ Launch an application. """ - self.commands.run( + handle = self.commands.run( f"gtk-launch {application} {uri or ''}", background=True, timeout=0 ) + handle.disconnect()