我已经定义了一个应用程序
{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
由于某种原因)。我不确定要发布多少代码,所以我将它保持在wand
模块本身的最低限度。如果我需要发布其他文章,请告诉我。
-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").
并获得预期的回复。当它通过主管启动时,它会挂起而展示我之前描述的行为。
答案 0 :(得分:1)
不是答案,但在这种情况下我会做什么。我将使用gen_server:cast并将在gen_server中处理超时,在完成所有工作后,我将向请求者发送带有结果的响应。所以这种变化也会影响请求方。
但我可能在各方面都错了。
答案 1 :(得分:0)
在处理外部C程序时,似乎使用receive..after
而不是普通receive
强制执行kill。我不确定为什么其他措施不起作用......
...
receive
{State, {data, Data}} ->
{reply, decode(Data), State}
after 3000 ->
exit(wand_timeout)
end;
...
此外,此时您必须希望合法操作不会超过3000
。在这种特殊情况下,这不是问题,但可能是我向C程序添加了更多输出。