파이썬에서 rabbitmq의 브로커에 연결할때 보통 pika 를 사용한다
이 때 아래의 2가지 상황이 섞이면 문제가 생긴다
보통 2번째 처럼 한번에 긴 작업을 할경우 heartbeat를 굉장히 길게 잡거나 0으로 설정하게 되는데 그럼에도 일정시간 후 tcp연결이 비정상적으로 끊기고 브로커와 클라이언트에서 소켓연결이 끊겼음을 인지하지 못하면(fin을 받지 못함) 아래의 상황을 의심해봐야한다
로드밸런서에서는 유휴한 연결을 일정시간이 지나면 자동으로 해제하는 idle timeout 기능을 제공하는데 이 기능이 설정되어 있을 가능성이 매우 높다
이 경우 heartbeat로는 해결할 수 없다
rabbitmq의 heartbeat 값은 timeout시간이며 timeout/2 초마다 패킷을 보내게 된다. 이를 idle timeout시간 전에 보내도록 적절한 값을 넣으면 로드밸런서에서 연결을 끊지는 않는다
하지만 클라이언트에서 idle timeout 시간보다 2배이상 걸리는 작업을 수행하게 되면 위의 방법으로는 세션을 유지할 수 없다
이 때 TCP keepalive 기능을 사용하면 주기적으로 패킷을 보내게 되면서 해결할 수 있지만 pika 문서에서는 적절한 가이드를 찾지 못 했고 검색해도 나오지가 않았는데
다행히 pika github에 테스트코드에서 예시를 찾아볼 수 있었다 ConnectionParameters의 tcp_options에 딕셔너리로 TCP_KEEPIDLE, TCP_KEEPCNT, TCP_KEEPINTVL 중 1개이상을 설정해주면 TCP keepalive가 설정된다
credentials = pika.PlainCredentials(USERNAME, PASSWORD)
parameters = pika.ConnectionParameters(HOST,
PORT,
VHOST,
credentials,
heartbeat=0,
tcp_options={'TCP_KEEPIDLE':60})
connection = pika.BlockingConnection(parameters)