I think this is because the server sends traffic and therefore does not need to send a heartbeat. A workaround is to hack IO.on_read to set the Channel0._last_heartbeat to time.time() if the frame is not for Channel0.