현상
Rubymine 에서 개발을 하다가 debug 모드로 실행하고 break point 걸어서 보려고 하면 Exception in DebugThread loop: Bad file descriptor(Errno::EBADF) 이런 오류가 발생하면서 안 되는 경우가 있다.
해결
결론적으로는 Rails.env = development 인 상황에서도 Rails + puma 가 multi processes 로 동작하도록 구성돼 있는 것을 single process 로 동작하도록 구성하면 해결이 된다.
원인
puma 가 multi processes 모드(a.k.a. cluster mode)로 실행되면
[38032] * Master PID: 38032
[38032] - Worker 2 (PID: 38156) booted in 0.2s, phase: 0
[38032] - Worker 3 (PID: 38157) booted in 0.2s, phase: 0
[38032] - Worker 0 (PID: 38154) booted in 0.21s, phase: 0
[38032] - Worker 1 (PID: 38155) booted in 0.21s, phase: 0
이렇게 Master process 와 이로부터 forked 된 child processes 를 확인할 수 있다.
그런데 Rubymine 에서 rails 를 debugger 로 실행시키면 아래와 같이 별도의 port 를 추가로 사용하게 되는데,
그 별도의 port 는 puma master PID 가 점유하고 있는 port 이다.
즉, debugger 는 puma 의 master process 에 붙어있는 것이다.
그런데 puma 서버에 http request 를 보내면, master process 가 요청을 처리하지 않고 child processes 중 하나가 처리하게 되는데(위 스샷에서는 PID 38155) 이 process 입장에서는 연결된 debugger 를 찾을 수 없으니(File Descriptor 를 이용해서 찾나 봄) 이런 오류가 발생하게 된 것으로 보인다.
이 문제를 해결하기 위해 puma.rb 의 workers 수를 0으로 변경하여 주면, 아래와 같이 single process(single mode) 만 뜨게 되는데, 아까완 달리 main PID 하나가 정확하게 debugger 가 사용하는 port 를 점유한 PID 와 일치하는 것을 볼 수 있다.
이 상태에서 특정 코드를 실행하도록 하는 trigger(e.g. http request)를 실행하면
문제없이 잘 작동함을 볼 수 있다!