Summary#
Backend graceful shutdown은 단순히 SIGTERM을 받고 서버 소켓을 닫는 문제가 아니다. 실제 장애는 보통 다음 네 가지 경계에서 발생한다.
- descendant process reaping 실패: 직접 child만 종료하고 grandchild / detached subprocess / process group을 놓쳐 orphan, zombie, 리소스 누수가 생긴다.
- pending async work drain 실패: background task, worker thread, queue consumer, timer, in-flight promise/future를 취소하거나 기다리지 않아 데이터 유실·중복 처리·불완전 flush가 발생한다.
- signal propagation 실패: parent service가 받은
SIGTERM/SIGINT가 child process tree에 전달되지 않거나, container / systemd / shell wrapper 경계에서 신호가 끊긴다. - duplicate teardown guard 부재:
SIGTERM,SIGINT, health-check failure, uncaught exception, orchestrator timeout 등이 동시에 shutdown path를 호출하면서 cleanup이 중복 실행된다.
안전한 graceful shutdown 설계는 “신호 수신 → 신규 작업 차단 → 하위 실행 단위에 종료 전파 → pending work drain with deadline → 강제 종료 fallback → wait/reap → idempotent teardown 완료” 순서로 모델링하는 것이 좋다.
Key Points#
- Process tree 전체를 shutdown 대상으로 보아야 한다
child.kill()또는 단일 PID 대상 signal은 보통 직접 child 하나에만 적용된다.- backend가 subprocess를 띄우고 그 subprocess가 다시 grandchild를 만들면, parent가 직접 추적하지 않는 descendant가 남을 수 있다.
-
장기 실행 서비스에서는 subprocess를 process group/session 단위로 관리하거나, supervisor/systemd/container runtime의 kill 정책을 명확히 설정해야 한다.
-
Zombie process는 kill이 아니라 wait/reap 문제다
- 종료된 child는 parent가 exit status를 수거하기 전까지 zombie가 될 수 있다.
- child에게 signal을 보낸 뒤에도
wait,waitpid, language runtime의Process.wait(),cmd.Wait()등에 해당하는 reap 단계가 필요하다. -
특히 서버가 PID 1로 container 안에서 실행될 경우, orphaned descendant reaping을 제대로 하지 못하면 zombie accumulation 문제가 생길 수 있다.
-
Signal propagation은 runtime마다 다르게 동작한다
- Node.js, Python, Go 등은 child process 생성 API가 있지만, 기본 동작이 “전체 process tree에 signal 전파”를 보장한다고 가정하면 위험하다.
- shell wrapper, npm script, bash entrypoint, process manager, systemd unit, Kubernetes termination flow가 중간에 있으면 실제 signal 수신 주체가 달라질 수 있다.
-
systemd에서는
KillMode,KillSignal,TimeoutStopSec같은 설정이 하위 process 종료 방식에 영향을 준다. -
Pending async work는 ‘취소’와 ‘drain’을 구분해야 한다
- graceful shutdown에서 모든 작업을 무조건 끝까지 기다리면 shutdown이 무한정 지연될 수 있다.
- 반대로 즉시 cancel하면 queue ack, DB transaction, file flush, message publish, telemetry export가 중간 상태로 남을 수 있다.
-
권장 패턴:
- 신규 요청 / 신규 job intake 중단
- 이미 시작한 critical section은 짧은 deadline 내 완료 허용
- non-critical background task는 cancellation token / context / abort signal로 중단 요청
- deadline 초과 시 강제 종료 fallback
- flush, close, commit, ack 순서를 명시
-
Event loop shutdown은 pending task visibility가 핵심이다
- asyncio, Node.js Promise, worker thread, timer, interval, queue consumer 등은 “서버 close 완료”와 별개로 남아 있을 수 있다.
- shutdown 시점에 남은 task 목록을 관찰하고, cancellation 후 gather/wait하는 정책이 필요하다.
-
unhandled rejection, cancelled task exception, executor thread leak을 shutdown noise로 무시하면 실제 데이터 유실을 놓칠 수 있다.
-
Duplicate teardown guard는 필수다
- 동일 프로세스가
SIGTERM과SIGINT를 연속으로 받거나, shutdown hook과 exception handler가 동시에 실행될 수 있다. - cleanup 함수가 idempotent하지 않으면 다음 문제가 생긴다:
- DB pool double close
- message consumer double ack/nack
- temp directory double delete
- child process kill/wait race
- metrics/exporter flush 중복
- 최소한 atomic state machine을 둔다:
RUNNINGSTOPPINGDRAININGFORCINGSTOPPED
-
첫 shutdown trigger만 full teardown을 시작하고, 후속 trigger는 deadline 단축 또는 force-kill escalation으로 처리한다.
-
추천 shutdown sequence 1.
SIGTERM/SIGINT수신 2. atomic guard로 shutdown once 보장 3. readiness false / 신규 트래픽 차단 4. HTTP listener / queue intake / scheduler stop 5. child process group 또는 tracked children에 종료 signal 전파 6. async background work cancellation 요청 7. bounded drain: in-flight request, transaction, queue ack, telemetry flush 8. childwait/reap 9. deadline 초과 시 force kill 10. final close: DB pool, file handle, logger, metrics exporter 11. exit code 결정
Cautions#
- 이 초안은 공개적으로 알려진 runtime / OS / service manager 문서에 근거한 일반 backend shutdown capsule이다. 특정 내부 프로젝트나 특정 장애 사례를 단정하지 않는다.
- 현재 환경에서는 사용자가 요구한 별도
WebSearch도구를 실제로 호출할 수 없었다. 따라서 아래 Sources는 공개 문서로 알려진 신뢰 가능한 URL 후보이며, 최종 capsule 확정 전 최신 문서 확인이 필요하다. - “child process 종료”와 “descendant process tree 종료”는 동일하지 않다. 언어별
kill()API 이름만 보고 process tree 전체 종료를 보장한다고 해석하면 안 된다. - graceful shutdown deadline은 workload별로 달라야 한다. HTTP request, queue consumer, DB migration worker, media encoder, ML batch job은 같은 drain 정책을 적용하기 어렵다.
- orchestrator의 강제 종료 timeout이 애플리케이션 내부 graceful timeout보다 짧으면 내부 로직은 완료되지 못한다. Kubernetes
terminationGracePeriodSeconds, systemdTimeoutStopSec, process manager timeout을 함께 맞춰야 한다. - duplicate teardown guard는 “cleanup을 한 번만 실행”하는 것뿐 아니라, 두 번째 signal에서 강제 종료로 escalate할지 여부까지 정책화해야 한다.
Sources#
- https://www.freedesktop.org/software/systemd/man/latest/systemd.kill.html
- https://nodejs.org/api/child_process.html
- https://docs.python.org/3/library/subprocess.html
- https://docs.python.org/3/library/asyncio-task.html
- https://pkg.go.dev/os/exec
- https://man7.org/linux/man-pages/man2/waitpid.2.html
- https://man7.org/linux/man-pages/man7/signal.7.html
- https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination
Related#
- Core API Long-Running Operation Contracts: 202 Accepted, Operation Resources, Cancellation, and Duplicate-Submit Failure Modes
- OpenTelemetry Distributed Tracing Failure Modes: Async Context Propagation, Span Boundaries, High-Cardinality Attributes, and Head-vs-Tail Sampling Interactions
- CQRS Read-Model Projection Failure Modes: Ordering, Idempotent Replay, Poison Events, and Rebuild Cutover
Sagwan Revalidation 2026-07-05T00:54:28Z#
- verdict:
ok - note: graceful shutdown 핵심 실패 모드와 권장 순서가 현재 practice와 부합함
Sagwan Revalidation 2026-07-06T06:59:52Z#
- verdict:
ok - note: 현재 관행과 사실에 부합하며 재사용에 문제 없음.
Sagwan Revalidation 2026-07-07T12:54:27Z#
- verdict:
ok - note: 일반 원칙 중심이라 최신 관행과 충돌 없고 재사용 가능함
Sagwan Revalidation 2026-07-08T19:01:21Z#
- verdict:
ok - note: 일반적 종료 설계 원칙으로 현재 practice와 충돌 없음
Sagwan Revalidation 2026-07-10T23:55:29Z#
- verdict:
ok - note: 일반 원칙과 권장 흐름이 현재 practice와도 일치해 재사용 가능
Sagwan Revalidation 2026-07-12T17:21:47Z#
- verdict:
ok - note: 일반 원칙 위주라 최신 관행과 충돌 없고 재사용 가능함
Sagwan Revalidation 2026-07-14T14:02:02Z#
- verdict:
ok - note: 일반 원칙 위주라 최신 practice와 충돌하지 않고 재사용 가능함
Sagwan Revalidation 2026-07-16T14:32:50Z#
- verdict:
ok - note: 일반 원칙 위주라 최근 관행과 충돌 없고 재사용 가능함
Sagwan Revalidation 2026-07-18T16:10:57Z#
- verdict:
ok - note: 일반 원칙과 failure mode가 현재 practice와도 일치해 변경 불필요
Sagwan Revalidation 2026-07-20T17:23:57Z#
- verdict:
ok - note: 일반 원칙 중심이라 최신 practice와 충돌 없이 재사용 가능.