在不通过通用测试的情况下杀死 gen_server

Posted

技术标签:

【中文标题】在不通过通用测试的情况下杀死 gen_server【英文标题】:Killing a gen_server without failing the Common Test 【发布时间】:2021-09-25 15:30:15 【问题描述】:

我实现了一个故意崩溃的模块(以测试另一个模块的功能,该模块正在监视它)。问题是,当这个 gen_server 崩溃时,它也会导致通用测试失败。我尝试使用 try/catch 并设置 process_flag(trap_exit, true),但似乎没有任何效果。

以下是一些相关代码:

-module(mod_bad_process).

% ...

%% ct calls this function directly
kill() ->
    gen_server:call(?MODULE, update_behavior, kill).

% ...

handle_cast(update_behavior, Behavior, _From, State) ->
    case Behavior of 
        kill -> stop, killed, State;
        _ -> reply, ok, State#state := Behavior
    end;

% ...

以及常见的测试:

% ...

-define(BAD_PROC, mod_bad_process).

% ...

remonitor_test(_Conf) ->
    InitialPid = whereis(?BAD_PROC),
    true = undefined =/= InitialPid,
    true = is_monitored_gen_server(?BAD_PROC),
    mod_bad_process:kill(),                     % gen_server crashes
    timer:sleep(?REMONITOR_DELAY_MS),
    FinalPid = whereis(?BAD_PROC),
    true = InitialPid =/= FinalPid,
    true = undefined =/= FinalPid,
    true = is_monitored_gen_server(?BAD_PROC).

% ...

还有来自 ct 的错误:

*** CT Error Notification 2021-07-16 16:08:20.791 ***
gen_server:call failed on line 238
Reason: killed,gen_server,call,...

=== Ended at 2021-07-16 16:08:20
=== Location: [gen_server,call,238,
              mod_bad_process,kill,48,
              monitor_tests,remonitor_test,62,
              test_server,ts_tc,1784,
              test_server,run_test_case_eval1,1293,
              test_server,run_test_case_eval,1225]
=== === Reason: killed,gen_server,call,
                                     [mod_bad_process_global,
                                      update_behavior,kill]
=== 
*** monitor_remonitor_test failed.
    Skipping all other cases in sequence.

关于如何在不通过常见测试的情况下获得此功能的任何想法?

【问题讨论】:

请显示常见的测试代码和崩溃。 CT码里是trap_exit吗? @JoséM 添加了通用测试代码。是的,我在mod_bad_process:kill() 之前尝试了trap_exit。我还尝试将其包装在 try catch 中 您能分享一下 CT 报告的崩溃情况吗?另外,这 3 个进程(测试运行程序、监视器和 BAD_PROC)是如何链接在一起的?此外,它可能对您有用:您可以使用 process_info(...[links|monitors|monitored_by]) 检查进程的链接和监视器 @JoséM 我更新了我的帖子以显示错误和堆栈跟踪。我不确定测试运行器是如何连接的,但是监视器正在监视 mod_bad_process(正如人们所期望的那样),并且它们都具有到未知进程的链接(可能是它们的主管,绝对不是彼此)。我想 mod_bad_process gen_server 可能链接到运行我的测试的进程,但我认为这不太可能,因为我以前有间接杀死 gen_server 的代码(基本上是通过将坏 proc 的状态设置为 kill 并等待它要检查),效果很好。 你的情况很像这个……medium.com/erlang-battleground/… 【参考方案1】:

问题是我的 try/catch 尝试与实际错误的模式不匹配。这是修复:

-module(mod_bad_process).

% ...

kill() ->
    try gen_server:call(?MODULE, update_behavior, kill) of 
        _ -> error(failed_to_kill)
    catch
        exit:killed, _ -> ok
    end.
% ...

【讨论】:

以上是关于在不通过通用测试的情况下杀死 gen_server的主要内容,如果未能解决你的问题,请参考以下文章

如何在不显示通知的情况下 startForeground()?

如何在不杀死未完成的芹菜任务的情况下重新启动heroku应用程序

如何在不“杀死” Unity 的情况下在 Ubuntu 14.04 中安装 Matlab MCR?

Firebase crashlytics 中的非致命错误能否在不杀死应用程序 React Native 的情况下记录错误

如何在不杀死 /health 的情况下将我的 Spring Boot 应用程序默认为 application/xml?

当应用程序处于状态后台或被杀死时,如何在不点击通知的情况下存储 iOS 远程通知?