AMQP 连接丢失不会杀死父进程,因此永远不会发生重新连接

Posted

技术标签:

【中文标题】AMQP 连接丢失不会杀死父进程,因此永远不会发生重新连接【英文标题】:AMQP connection lost doesn't kill parent process, so reconnection never happens 【发布时间】:2021-02-16 07:06:02 【问题描述】:

我的 GenServer 有初始化功能。主管正在照顾它,应该在退出时重新启动它。

  def init(_opts) do
    username = get_conf(:username)
    password = get_conf(:password)
    host = get_conf(:host)
    port = get_conf(:port)
    vhost = String.replace(get_conf(:vhost), "/", "%2f")
    :ok, conn = Connection.open("amqp://#username:#password@#host:#port/#vhost")
    :ok, chan = Channel.open(conn)
    state = %State
      exchange: get_conf(:exchange),
      channel: chan,
      routing_key: get_conf(:routing_key)
    
    :ok, state
  end

当我使用sudo service rabbitmq-server restart 重新启动 RabbitMQ 时,新连接未建立。

在调试栏中,我看到以下内容: 当我单击连接 pid 时,我收到消息说进程不再存在。似乎这个过程已经死了,父母AmqpTransport对此一无所知。 我怎样才能让AmqpTransport和它的孩子Connection一起死?

【问题讨论】:

【参考方案1】:

通过添加trapping exits 并链接到Connection 进程来修复它。此外,我在连接期间出现模式匹配错误以避免reached_max_restart_intensity

  @restart_delay 2000 # 2 seconds

  def init(_opts) do
    Process.flag(:trap_exit, true)
    send(self(), :connect)
    :ok, nil
  end

  def handle_info(:connect, state) do
    #...
    case Connection.open("amqp://#username:#password@#host:#port/#vhost") do
      :ok, conn ->
        Process.link(conn.pid)
        # ...
        :noreply, state
      :error, :econnrefused ->
        Logger.error("amqp transport failed with connection refused")
        Process.send_after(self(), :connect, @restart_delay)
        :noreply, nil
    end

  end

  def handle_info(:EXIT, pid, reason, state) do
    Logger.error("amqp transport failed with #inspect(reason)")
    Process.unlink(pid)
    Process.send_after(self(), :connect, @restart_delay)
    :noreply, nil
  end  

【讨论】:

Process.flag(:trap_exit, true) 那里是多余的,这应该在这个过程的init/1 回调的某个地方完成,不需要每次重新建立连接时都调用它。此外,为清楚起见,您可能希望在 handle_info(:EXIT, _pid, reason, state) 中调用 Process.unlink/1 以取消链接已终止的进程。 @AlekseiMatiushkin,谢谢!在我的回答中反映了您的建议。

以上是关于AMQP 连接丢失不会杀死父进程,因此永远不会发生重新连接的主要内容,如果未能解决你的问题,请参考以下文章

Erlang 套接字发送超时永远不会发生

当 Promise 永远不会解决时会发生啥? [复制]

PostgreSQL JDBC 套接字超时不会杀死后台进程

Vue cli 3道具(父到子)子在父变量更改后永远不会更新

非阻塞等待子进程退出

taskkill 不会杀死进程