我已经定义了一个应用程序
{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").
并得到预期的响应。当它通过主管启动时,它会挂起并表现出我之前描述的行为。