CopilotClient.stop() leaks the CLI server's child process tree on Windows (orphaned node/copilot.exe per session)
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 52/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Tranquilo
- Stack tecnológico
- python
- Área
- operating-systems, tooling
Línea de trabajo
Inspecciona client.py, especialmente CopilotClient.stop() y la creación de procesos de StdioRuntimeConnection; después, reproduce el bucle de Windows create_session()/stop() del issue mientras realizas el seguimiento de los procesos descendientes. Compara el comportamiento del ciclo de vida entre Windows y POSIX, y considera los enfoques indicados de Job Object o process-group. Se considera terminado cuando detener un cliente iniciado no deja procesos node.exe o copilot.exe descendientes huérfanos.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
On Windows, CopilotClient.stop() does not terminate the CLI server's child process tree — only the top-level launcher process. Every create_session() / stop() cycle therefore orphans a full copilot process tree (node.exe + the copilot.exe broker/worker/webview helpers) that survives until its own idle timeout. In a long-running app that creates one client/session per unit of work (e.g. a batch/eval harness), this is a deterministic ~1 leaked process tree per session, which accumulates and eventually OOMs the host.
Environment
github-copilot-sdk(Python)1.0.0b7(also visible by inspection in currentclient.py)- Copilot CLI runtime
1.0.66-0 - Windows 11, Python 3.11 (miniconda)
- Transport:
StdioRuntimeConnection,use_logged_in_user=True
Root cause
CopilotClient.stop() only calls terminate() / kill() on its own launcher Popen (self._process):
# client.py (stop)
if self._process and not self._is_external_server:
self._process.terminate()
try:
self._process.wait(timeout=5)
except subprocess.TimeoutExpired:
self._process.kill()
self._process = None
On Windows, terminating the launcher does not cascade to its descendants. The launcher (copilot.cmd → cmd.exe) spawns node.exe, which spawns the real copilot.exe server + helper processes; these are left orphaned and alive after stop().
Reproduction
import asyncio, psutil
from copilot import CopilotClient, StdioRuntimeConnection
CLI = r"C:\Users\<you>\AppData\Roaming\npm\copilot.cmd"
def n_copilot():
return sum(p.info["name"] == "copilot.exe"
for p in psutil.process_iter(["name"]))
async def main():
for i in range(5):
client = CopilotClient(
connection=StdioRuntimeConnection(CLI, []),
use_logged_in_user=True,
)
session = await client.create_session()
await session.send("hello")
# ...consume events until SessionIdle...
await session.disconnect()
await client.stop()
print(f"iter {i}: copilot.exe alive = {n_copilot()}")
asyncio.run(main())
Observed (Windows): copilot.exe alive grows 1, 2, 3, 4, 5 — one orphaned tree per iteration, none reaped by stop().
Expected
After await client.stop() (for a client that spawned the server), the entire CLI server process tree should be terminated, leaving no orphaned node.exe / copilot.exe processes.
Workaround
Capture the launcher PID after create_session() and kill the whole tree explicitly on teardown — e.g. psutil.Process(pid).children(recursive=True) + kill all (enumerate before killing the parent), or taskkill /F /T /PID on Windows / os.killpg on POSIX.
Suggested fix
Have the SDK own the process-tree lifecycle so stop() reaps descendants:
- Windows: assign the launcher to a Job Object with
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, so the OS atomically kills the tree when the job/handle closes. - POSIX: spawn with
start_new_session=Trueandos.killpg(os.getpgid(pid), SIGKILL)on stop. - Or a
psutil-based recursive child kill insidestop().
This is likely related to the CLI-side reports of orphaned processes (e.g. github/copilot-cli#1368, #2279) but is reproducible purely through the SDK's own create_session()/stop() lifecycle.
- Lenguaje dominante
- TypeScript
- Estrellas
- 10.5k
- Forks
- 1.5k
- Merge medio
- 1 d 11 h
- PR fusionados (30 d)
- 81
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de github/copilot-sdk
-
Clarify SDK architecture and in-process runtime transportPosiblemente ocupada @KalebCole la tomó hace 3 días. Abiertodocumentation
Dificultad 1/5 Menos de una hora Aptitud para principiantes 92/100
github/copilot-sdk#2804 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Python ModelLimits drops max_output_tokens from model metadataPosiblemente ocupada @HDMowri la tomó hace 5 días. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
github/copilot-sdk#2798 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
github/copilot-sdk#2793 ·
Los mantenedores suelen responder en 1 día
-
agentic-workflows
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
github/copilot-sdk#2782 ·
Los mantenedores suelen responder en 1 día
-
Rust: subagent lifecycle hooks are logged as unknownPosiblemente ocupada @hackberry-lab la tomó hace 7 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
github/copilot-sdk#2781 ·
Los mantenedores suelen responder en 1 día
Todos los issues de github/copilot-sdk
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
AOSSIE-Org/DebateAI#611 ·
Los mantenedores suelen responder en 3 días
-
Upgrade node-libzim to 4.7.0Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
openzim/mwoffliner#2933 ·
Los mantenedores suelen responder en 1 día
-
Use the README category name for website links and submissionsPosiblemente ocupada @dajiaohuang la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
birobirobiro/awesome-shadcn-ui#647 ·
Los mantenedores suelen responder en 2 días
-
Twake Drive picker: closePicker() never destroys the intent (stop() is on the promise returned by start(), not by create())Posiblemente ocupada @chibenwa la tomó hoy. Abiertoclaude
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
linagora/twake-calendar-frontend#1498 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Add: Valea Prahovei TV RO SDAbiertocheck:passed streams:add
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
Los mantenedores suelen responder en 1 día