Erlang 处理OTP中的超时

Erlang 处理OTP中的超时,erlang,timeout,otp,Erlang,Timeout,Otp,我已经定义了一个应用程序 {application, ps_barcode, [{description, "barcode image generator based on ps-barcode"}, {vsn, "1.0"}, {modules, [ps_barcode_app, ps_barcode_supervisor, barcode_data, wand, ps_bc]}, {registered, [ps_bc, wand, ps_barcode_supervisor

我已经定义了一个应用程序

{application, ps_barcode,
 [{description, "barcode image generator based on ps-barcode"},
  {vsn, "1.0"},
  {modules, [ps_barcode_app, ps_barcode_supervisor, barcode_data, wand, ps_bc]},
  {registered, [ps_bc, wand, ps_barcode_supervisor]},
  {applications, [kernel, stdlib]},
  {mod, {ps_barcode_app, []}},
  {start_phases, []}]}.
主管
init
看起来像

init([]) ->
    {ok, {{one_for_one, 3, 10},
      [{tag1, 
        {wand, start, []},
        permanent,
        brutal_kill,
        worker,
        [wand]},
       {tag2,
        {ps_bc, start, []},
        permanent,
        10000,
        worker,
        [ps_bc]}]}}.
这是一个条形码生成器,它使用C组件进行一些图像处理。如果要求系统处理不存在的文件或权限不足,系统会出错并正确重新启动,但有一个特定错误导致
wand
模块超时

GPL Ghostscript 9.04: Unrecoverable error, exit code 1
GPL Ghostscript 9.04: Unrecoverable error, exit code 1
wand.c barcode_to_png 65 Postscript delegate failed `/tmp/tmp.1337.95765.926102': No such file or directory @ error/ps.c/ReadPSImage/827

** exception exit: {timeout,{gen_server,call,
                    [wand,{process_barcode,"/tmp/tmp.1337.95765.926102"}]}}
     in function  gen_server:call/2 (gen_server.erl, line 180)
     in call from ps_bc:generate/3 (ps_bc.erl, line 19)
(Imagemagick错误不准确;该文件存在,但它是一个带有错误的Postscript文件,因此无法解释为正常;我假设这就是生成Ghostscript错误并导致程序挂起的原因,但我不确定它为什么无法返回)

我遇到的问题是:即使此超时返回一个错误,
wand
进程似乎在后台挂起(我的结论是,任何对
wand
的进一步调用都会返回另一个超时错误,包括
wand:stop
)。我不确定要发布多少代码,所以我将其保存在
魔杖
模块本身。如果我需要发布其他文章,请告诉我

-module(wand).

-behaviour(gen_server).

-export([start/0, stop/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
     terminate/2, code_change/3]).

-export([process/1]).

process(Filename) -> gen_server:call(?MODULE, {process_barcode, Filename}).

handle_call({process_barcode, Filename}, _From, State) ->
    State ! {self(), {command, Filename}},
    receive
      {State, {data, Data}} ->
        {reply, decode(Data), State}
    end;
handle_call({'EXIT', _Port, Reason}, _From, _State) ->
    exit({port_terminated, Reason}).

decode([0]) -> {ok, 0};
decode([1]) -> {error, could_not_read};
decode([2]) -> {error, could_not_write}.

%%%%%%%%%%%%%%%%%%%% generic actions
start() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
stop() -> gen_server:call(?MODULE, stop).

%%%%%%%%%%%%%%%%%%%% gen_server handlers
init([]) -> {ok, open_port({spawn, filename:absname("wand")}, [{packet, 2}])}.
handle_cast(_Msg, State) -> {noreply, State}.
handle_info(_Info, State) -> {noreply, State}.
terminate(_Reason, Port) -> Port ! {self(), close}, ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.

编辑:忘记提及,可能相关;挂起似乎只有在通过
application:load
/
application:start
运行应用程序时才会发生。如果我自己测试这个组件

c(wand).
wand:start().
wand:process("/tmp/tmp.malformed-file.ps").
它仍然是错误的,但是这个过程真的死了。也就是说,我能做到

wand:start().
wand:process("/tmp/tmp.existing-well-formed-file.ps").

并得到预期的响应。当它通过主管启动时,它将挂起并显示我前面描述的行为。

不是答案,而是在这种情况下我将做什么。我将使用gen_server:cast并在gen_服务器中处理超时,在所有工作完成后,我将向请求者发送带有结果的响应。因此,这些更改也会影响请求方


但我可能在各方面都错了。

不是答案,而是在这种情况下我会怎么做。我将使用gen_server:cast并在gen_服务器中处理超时,在所有工作完成后,我将向请求者发送带有结果的响应。因此,这些更改也会影响请求方


但是我可能在所有方面都错了。

似乎在处理外部C程序时,使用
receive..after
而不是普通的
receive
会强制终止。但我不知道为什么其他措施不起作用

...
receive
  {State, {data, Data}} ->
    {reply, decode(Data), State}
after 3000 ->
  exit(wand_timeout)
end;
...

此外,在这一点上,您必须希望合法操作所需的时间不会超过
3000
。在这种特殊情况下,这不是问题,但如果我向C程序添加更多输出,可能会出现问题。

似乎在处理外部C程序时,使用
receive..after
而不是普通的
receive
会强制终止。但我不知道为什么其他措施不起作用

...
receive
  {State, {data, Data}} ->
    {reply, decode(Data), State}
after 3000 ->
  exit(wand_timeout)
end;
...
此外,在这一点上,您必须希望合法操作所需的时间不会超过
3000
。在这种特殊情况下这不是问题,但如果我向C程序添加更多输出,可能会有问题