기술 · 실용 가이드
취소한 task를 await하다 CancelledError? controller shutdown을 삼키지 마세요
child cancellation 완료와 외부 controller cancellation이 동시에 발생할 수 있습니다. ownership, finally cleanup, outcome collection, propagation test를 분리하세요.

child cancellation 완료와 외부 controller cancellation이 동시에 발생할 수 있습니다. ownership, finally cleanup, outcome collection, propagation test를 분리하세요.
CancelledError는 BaseException이며 cleanup 후 보통 다시 전파합니다. Task.cancel은 요청이며 coroutine 수락을 보장하지 않습니다.
1. task owner와 trigger 기록
controller, owned children, cancel source, sibling fate를 기록하고 except-pass로 시작하지 않습니다.
await child의 CancelledError는 child 종료 또는 controller 외부 cancel일 수 있어 type만으로 origin을 알 수 없습니다.
2. child cleanup은 finally
child resources는 try/finally에서 해제하고 cancellation을 보통 다시 전파합니다. cleanup await도 취소될 수 있습니다.
async finalization에는 작은 boundary를 두고 shield가 무한 shutdown이 되지 않게 합니다.
3. TaskGroup 또는 gather 선택
scope가 모든 child를 소유하고 sibling failure를 연동하면 TaskGroup을 씁니다. context exit가 모두 기다립니다.
independent child outcome은 gather(return_exceptions=True)로 모으고 gather 자체 cancel은 전파됩니다.
4. controller cancellation 보존
await child의 blanket catch를 피합니다. manual이면 child state와 current_task().cancelling을 기록하고 controller cancel은 다시 던집니다.
state를 지우려고 uncancel하지 마세요. suppression은 예외적이고 의도적인 결정입니다.
5. 동시 cancellation 테스트
child-only, controller-only, same-turn을 테스트해 cleanup, states, propagation을 assert합니다.
exit에서는 owned tasks만 audit하고 pending 또는 unretrieved exception이 없는지 확인합니다.
