![](/img/trans.png)
[英]Using OTP/Erlang as a part of the component-based architecture of a web application
[英]Erlang OTP application design
當我將一些代碼轉換為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}}.
在此設計中,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};
do_crawl產生了大量的進程和請求,用於處理通過http進行爬網的工作。
問題,最終是:實際抓取應該在哪里發生? 從上面可以看出,我一直在試驗觸發實際工作的不同方式,但仍然缺少一些對於整合事物的方式至關重要的概念。
注意:為簡潔起見,省略了一些OTP管道 - 管道就在那里,系統全部掛在一起
如果我的問題出錯,我會道歉。
我可以提出一些建議,以指導您正確的方向(或我認為是正確的方向:)
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.
所以,你可能希望有類似的東西:
-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}}.
我冒昧地建議對這些孩子進行暫時重啟,因為這對於這類工作人員是有意義的(如果他們沒有完成工作則重新啟動,如果他們沒有正常完成則不重啟)
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, ...
請注意,您的工作可以包含在此gen_fsm過程中,也可以考慮根據您的特定需求為其生成單獨的過程。
如果認為有必要,您可能希望為爬網的不同階段提供多個州名。
無論哪種方式,希望這將有助於以某種OTP方式設計您的應用程序。 如果您有任何問題,請告訴我,如果有必要,我很樂意添加一些東西。
我對此問題的解決方案是查看Erlang Solutions“作業”應用程序,該應用程序可用於調度作業(即請求頁面)並讓單獨的系統處理每個作業,綁定並發性等等。
然后,您可以將新網址提供給進程crawl_sched_mgr
,該進程會過濾網址,然后生成新作業。 你也可以讓請求者自己做。
如果你不想使用工作,Yurii的建議是要走的路。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.