Replace brittle timeout with a background heartbeat thread

@thieman