LLM 데이터 라벨링 업무를 하는데, 파이썬에서 flask를 이용해서 서버를 올려야하는게 있었다. 일단 서버는 올렸는데 프론트 서버에서 요청을 보내니 자꾸 CORS 에러가 떴다. CORS 관련된 것들 아무리 고쳐봐도 해결이 안 되길래 구글링을 좀 해보니,
맥북 airplay 기능이 5000번 포트를 사용한다고 한다.
파이썬 flask 서버의 기본 포트 또한 5000번 이다.
airplay 끄니 해결됐다.
가끔 이런 어이없는 에러를 마주하면 헛웃음이 난다.
글쓰던 중 갑자기 의문점이 들었다.
포트 충돌이라면 애초에 파이썬 서버가 올라가면 안 되지 않나?
답은 디버그 모드와 프로덕션 모드의 프로세스 실행 방식의 차이 때문에 가능하다는 것이다.
(라고 생각했지만 아래의 의문2를 풀어나가다가 이게 아닐 수도 있겠다는 생각을 하게 되었다.)
내 코드는 app.run(debug=True) 이렇게 디버그 모드로 실행이 되고있었다. 이때는 서버가 올라갔다.
근데 app.run()으로 프로덕션 모드로 실행하니 포트 충돌 에러가 뜨며 서버 자체가 올라가지 않았다.
디버그 모드와 프로덕션 모드의 차이는 프로세스 실행 방식이다. 디버그 모드는 두 개의 프로세스를 실행시켜 코드에 수정사항이 생기면 바로 반영할 수 있게한다. 반면 프로덕션 모드는 하나의 프로세스만 실행된다.
(디버그 모드에서 코드 변경이 감지될 경우 새 프로세스를 생성하고 이것으로 flask를 실행한다.)
디버그 모드가 실행될 때 첫 번째 프로세스는 생성되고 바로 죽는데 이때 5000포트를 잠깐 잡고있다가 죽는다. 이후 flask의 SO_REUSEADDR를 사용해서, 사용이 끝난 포트를 즉시 다시 사용할 수 있도록 허용한다. (일반적으로 OS는 소켓이 닫힌 이후에도 일정 시간동안 포트를 사용하지 못하게 대기해둔다.) 그래서 첫 번째 프로세스가 종료되면서 -> 5000번 포트가 사용 가능 상태가 되고 -> 두 번째 프로세스가 그걸 잡아서 실행한 것이다.
(첫 번째 프로세스가 애초에 어떻게 이미 점유된 5000번 포트를 잡았나? 이건 찾아봤는데 아직 못찾았다 ㅠㅠ)
반면 프로덕션 모드에서는 SO_REUSEADDR를 사용하지 않고 하나의 프로세스만 실행되기 때문에 5000번이 이미 점유되어 있다면 충돌이 발생한다.

의문1을 풀어내던 중 코드를 프로덕션 모드로 실행해봤는데 실행이 됐다. airplay 기능이 켜져있는데도 실행이 됐다. 우연인가 싶어 몇십분동안 간간히 실행해봤는데 계속 실행이 됐다.
아까는 정말로 디버그 모드만 실행이 됐었는데 지금은 프로덕션 모드까지 실행이 되니 당황스럽다. 의문1에 대한 답 조차도 무의미해졌다.
해결방법의 정리가 아니라 이 일이 발생한 과정의 시간순 정리이다.
1. 디버그 모드로 실행했을 때 서버가 올라가긴 했지만 계속해서 CORS 에러가 났다.
2. 프로덕션 모드로 실행을 하니 5000번 포트가 이미 점유되었다며 실행조차 되지 않았다.
3. 5000번 포트는 맥북의 airplay 기능이 점유하고 있었다. 이 기능을 비활성화하니 문제가 해결됐다. 디버그 모드에서도 CORS에러가 안 뜨고, 프로덕션 모드도 문제없이 실행되었다.
4. 업무 마무리 후 airplay를 다시 활성화했다.
5. 위의 의문1, 의문2를 정리하던 중 아까 쓰던 코드를 다시 실행해봤는데 포트 충돌 없이 실행이 된다. 디버그 모드와 프로덕션 모드에서 둘 다 된다.
왜 아까는 안 되고 지금은 될까
진짜 왜지
검색해도 자료가 너무 적다
미래의 발전한 내가 와서 이 글을 수정할 날이 오길..
https://github.com/viniciuschiele/flask-apscheduler/issues/139