如何在 gen_server:terminate/2 中停止其他应用程序?

问题描述

我正在使用 erlang OTP 创建自己的服务器,但在使用 Mnesia 时遇到了问题。

我在我的工人的 gen_server:init/1 中启动 Mnesia,并在同一个工人的 gen_server:terminate/2 中停止它。 不幸的是,当通过调用 mnesia:stop/0application:stop(myApplication) 调用函数 init:stop() 时,应用程序卡住并以这样的方式结束:

=SUPERVISOR REPORT==== 23-Jun-2021::16:54:12.048000 ===
    supervisor: {local,temp_sup}
    errorContext: shutdown_error
    reason: killed
    offender: [{pid,<0.159.0>},{id,myMnesiaTest_sup},{mfargs,{myMnesiaTest_sup,start_link,[]}},{restart_type,permanent},{shutdown,10000},{child_type,supervisor}]

当然,这不会发生在 gen_server:terminate/2 没有通过将 trap_exit 标志设置为 false 来调用时,但 Mnesia 也不会停止。

我不知道为什么一个应用程序不能在其他应用程序中停止,我想知道如果我在我的应用程序结束时不调用 mnesia:stop() 就可以了。

解决方法

当您的应用程序停止时您无法停止 Mnesia 的原因是当时 git -c http.sslVerify=false clone https://<github_username>:<personal_access_token>@github.com/<path/to/repo> 进程正忙于停止您的应用程序。这是一个典型的死锁情况,当一个 git -c http.sslVerify=false clone https://140.82.121.4/<path/to/repo> (在这种情况下是间接的)对另一个 http.sslVerify=false 执行同步调用,而后者又想对第一个进行同步调用。

您可以通过在应用程序停止后异步关闭 Mnesia 来打破僵局。例如,尝试从您的 application_controller gen_server 拨打电话。 (只是生成一个进程来执行调用并不理想,它仍然属于您的应用程序,并且会在应用程序终止时被杀死。)

但大多数情况下,您真的不必费心阻止 Mnesia。按照惯例,Erlang 应用程序会在停止时启动它们的依赖项。如果您的应用程序被 gen_server 终止,它将负责停止所有其他应用程序,包括 Mnesia。