Tob*_*ede 8 architecture erlang erlang-otp
当我将一些代码转换为OTP应用程序时,我正在努力解决OTP开发模型.
我本质上是一个网络爬虫,我只是不知道在哪里放置实际工作的代码.
我有一个主管,开始我的工人:
-behaviour(supervisor).
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
init(_Args) ->
Children = [
?CHILD(crawler, worker)
],
RestartStrategy = {one_for_one, 0, 1},
{ok, {RestartStrategy, Children}}.
Run Code Online (Sandbox Code Playgroud)
在此设计中,Crawler Worker负责执行实际工作:
-behaviour(gen_server).
start_link() ->
gen_server:start_link(?MODULE, [], []).
init([]) ->
inets:start(),
httpc:set_options([{verbose_mode,true}]),
% gen_server:cast(?MODULE, crawl),
% ok = do_crawl(),
{ok, #state{}}.
do_crawl() ->
% crawl!
ok.
handle_cast(crawl}, State) ->
ok = do_crawl(),
{noreply, State};
Run Code Online (Sandbox Code Playgroud)
do_crawl产生了大量的进程和请求,用于处理通过http进行爬网的工作.
问题,最终是:实际抓取应该在哪里发生?从上面可以看出,我一直在尝试不同的触发实际工作的方法,但仍然缺少一些对于整合事物的方式至关重要的概念.
注意:为简洁起见,省略了一些OTP管道 - 管道就在那里,系统全部挂在一起
Yur*_*kii 11
如果我的问题出错,我会道歉.
我可以提出一些建议,以指导您正确的方向(或我认为是正确的方向:)
1(相当小,但仍然很重要)我建议将inets启动代码从该worker中取出并将其放入应用程序statup代码(appname_app.erl).据我所知,你正在使用钢筋模板,所以你应该有这些.
2现在,到必要的部分.为了充分利用OTP的管理程序模型,假设您想要生成大量的爬虫,那么使用simple_one_for_one主管而不是one_for_one会很有意义(请阅读http://www.erlang. org/doc/man/supervisor.html了解更多详细信息,但必不可少的部分是:simple_one_for_one - 一个简化的one_for_one管理程序,其中所有子进程都是动态添加相同进程类型的实例,即运行相同的代码.).因此,您不必仅启动一个监督过程,而是实际指定一个排序的"模板" - 关于如何启动正在执行的工作进程.这种类型的每个工作人员都是使用主管开始的:start_child/2 - http://erldocs.com/R14B01/stdlib/supervisor.html?i=1&search=start_chi#start_child/2.在您明确启动它们之前,这些工作者都不会启动.
2.1根据爬虫的性质,您可能需要评估工人需要的重启策略类型.现在,在您的模板中,您将其设置为永久性(但您有一种不同类型的受监督子项).以下是您的选择:
Restart defines when a terminated child process should be restarted. A permanent child process should always be restarted,
a temporary child process should never be restarted and a transient child process should be restarted only if it terminates
abnormally, i.e. with another exit reason than normal.
Run Code Online (Sandbox Code Playgroud)
所以,你可能希望有类似的东西:
-behaviour(supervisor).
-define(CHILD(I, Type, Restart), {I, {I, start_link, []}, Restart, 5000, Type, [I]}).
init(_Args) ->
Children = [
?CHILD(crawler, worker, transient)
],
RestartStrategy = {simple_one_for_one, 0, 1},
{ok, {RestartStrategy, Children}}.
Run Code Online (Sandbox Code Playgroud)
我冒昧地建议对这些孩子进行暂时重启,因为这对于这类工作人员是有意义的(如果他们没有完成工作则重新启动,如果他们没有正常完成则不重启)
2.2一旦您处理了上述项目,您的主管将处理任意数量的动态添加的工作流程; 它将监视并重新启动(如果需要)每个,这为您的系统稳定性和可管理性增加了很多.
3现在,一个工人流程.我假设每个爬虫都有一些特定的状态,它可能在任何给定的时刻.出于这个原因,我建议使用gen_fsm(有限状态机,更多关于它们的信息,请访问http://learnyousomeerlang.com/finite-state-machines).这样,您动态添加到主管的每个gen_fsm实例都应该在init/1中向自己发送一个事件(使用http://erldocs.com/R14B01/stdlib/gen_fsm.html?i=0&search=send_even#send_event/2).
单独的东西:
init([Arg1]) ->
gen_fsm:send_event(self(), start),
{ok, initialized, #state{ arg1 = Arg }}.
initialized(start, State) ->
%% do your work
%% and then either switch to next state {next_state, ...
%% or stop the thing: {stop, ...
Run Code Online (Sandbox Code Playgroud)
请注意,您的工作可以包含在此gen_fsm过程中,也可以考虑为其生成单独的过程,具体取决于您的特定需求.
如果认为有必要,您可能希望为爬网的不同阶段提供多个州名.
无论哪种方式,希望这将有助于以某种OTP方式设计您的应用程序.如果您有任何问题,请告诉我,如果有必要,我很乐意添加一些东西.