콘텐츠로 이동

고아 프로세스와 레지스트리

원인. 강제 종료된 호스트입니다. 프로세스 내부의 모든 방어 장치 — job object, 프로세스 그룹, 워치독 — 는 우리 코드가 얼마간 실행되어야 하는데, SIGKILL은 그 어느 것도 실행하지 않습니다. CLI는 살아남고, 이후의 어떤 호스트에게도 보이지 않습니다.

해결. 이것이 CliRegistry가 존재하는 이유입니다. spawn 시 등록하고, 종료 시 등록 해제하며, 시작 시 훑으십시오.

const registry = new CliRegistry(stateDirectory);
// 시작 시, 무엇이든 spawn하기 전에.
registry.prune();
for (const orphan of registry.orphans()) {
console.warn('left behind by a dead host:', orphan.pid, orphan.sessionId);
// 죽이거나, 죽일지 물어보십시오 — 결정은 호스트의 몫입니다.
}
// 각 세션 주변에서.
registry.register(childProcess, sessionId, workingDirectory);
session.onClose(() => registry.unregister(session.pid));

워치독도 함께 걸어두어, 흔한 경우 — 호스트가 정리 코드를 실행하지 않고 닫히는 것 — 를 프로세스 내부에서 잡으십시오.

new ParentWatchdog().start(() => {
session.stop('SIGKILL');
process.exit(0);
});

레지스트리가 아무것도 보고하지 않음

섹션 제목: “레지스트리가 아무것도 보고하지 않음”
원인 상세
state 디렉토리에 쓸 수 없음 register()는 설계상 쓰기 실패를 삼킵니다 — state 디렉토리에 쓸 수 없는 호스트라도 CLI는 실행할 수 있어야 합니다
pid가 다른 것으로 돌아옴 liveEntries()는 session id가 여전히 프로세스의 커맨드라인에 나타날 것을 요구하므로, 재사용된 pid는 올바르게 제외됩니다
identity를 읽을 수 없었음 commandLine()null을 반환하는 것은 죽었다는 뜻이 아니라 알 수 없다는 뜻이며, 알 수 없음은 의도적으로 일치로 치지 않습니다. 그 대안이 남의 프로세스를 죽이는 것이기 때문입니다

한 대화에서 모순된 답변이 나옴

섹션 제목: “한 대화에서 모순된 답변이 나옴”

원인. 두 CLI가 같은 대화에 덧붙이고 있고, 그래서 히스토리가 분기합니다.

해결. resume하기 전에 물어보십시오.

const existing = registry.findLive(sessionId);
if (existing) {
throw new Error(`session ${sessionId} is already driven by pid ${existing.pid}`);
}

이것이 고아 정리와 나란히 레지스트리가 존재하는 두 번째 이유입니다.

각 방어 장치는 서로 다른 방식으로 실패하며, 그래서 어느 하나만으로는 충분하지 않습니다. 전체 표는 아키텍처에 있습니다. 요약하면, 레지스트리는 프로세스 내부의 모든 방어 장치가 놓친 것을 사후에 잡습니다. spawn 시 파일을 쓰고 종료 시 지우는 것이, 호스트가 통째로 죽임당해도 살아남는 유일한 기록이기 때문입니다.