Erlang OTP 主管:当另一个子进程正在执行时,start_child 不起作用

问题描述 投票:0回答:1

我正在编写一个简单的 Erlang 应用程序来管理拍卖。当创建新的拍卖时,我想创建一个新的子进程来处理它。函数调用如下:

erws_dynamic_sup:start_auction_process(PhoneName, MinimumPrice, AuctionTime, EndDate);

因为我想监视它们,所以我尝试使用 simple_one_for_one 主管,它应该动态调用 start_child/2 添加它们。

这是supervisor的代码(erws_dynamic_sup):

start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

init([]) ->
    MaxRestarts = 10,
    MaxSecondsBetweenRestarts = 3600,
    SupFlags = #{strategy => simple_one_for_one,
                intensity => MaxRestarts,
                period => MaxSecondsBetweenRestarts},
    ChildSpecs = [
        #{
            id => erws_auction_handler,
            start => {erws_auction_handler, auction_handle, []},
            restart => transient,
            shutdown => 2000,
            type => worker,
            modules => [erws_auction_handler]
        }
    ],
    {ok, {SupFlags, ChildSpecs}}.


%%% Function to start an auction process
start_auction_process(PhoneName, MinimumPrice, AuctionTime, EndDate) ->

    case supervisor:start_child(?MODULE,
        [PhoneName, MinimumPrice, AuctionTime, EndDate]
    ) of
        {ok, AuctionPid} ->
            logger:info("[erws_dynamic_sup] start_auction_process => Start child executed correctly, PID: ~p~n", [AuctionPid]),
            AuctionPid;
        Error ->
            logger:info("[erws_dynamic_sup] start_auction_process => Error: ~p~n", [Error]),
            Error
    end.

管理拍卖过程的函数应由主管启动,如下所示(模块 erws_auction_handler):

auction_handle(Phone, Bid, AuctionTime, EndDate) ->
    logger:debug("[erws_auction_handler] auction_handle => Auction process started with pid: ~p~n", [self()]),
    erws_mnesia:save_auction(Phone, self()),

    Text = "Live auctions update requested!",
    gproc:send({p, l, {erws_auction_agent, {live_auctions}}}, {live_auctions_update, Text}),

    auction_receive(Phone, Bid, AuctionTime, EndDate).

%% Handle auction messages
auction_receive(Phone, Bid, AuctionTime, EndDate) ->
    receive
    %% Receive JOIN request from a Bidder
        {bidder_join, PhoneName} ->
            RemainingTime = get_time_remaining(EndDate),
            CurrentWinner = erws_mnesia:get_winner_bidder(PhoneName),
            case CurrentWinner of
                {WinnerEmail, _} ->
                    gproc:send({p, l, {?MODULE, PhoneName}}, {joined, Bid, RemainingTime, WinnerEmail});
                not_found ->
                    gproc:send({p, l, {?MODULE, PhoneName}}, {joined, Bid, RemainingTime, []})
            end,
            auction_handle(Phone, Bid, EndDate - erlang:system_time(second), EndDate);

      ... other cases

    end.

我遇到的问题是,只有当我进行一次拍卖时,这才可以正常工作。当我同时启动多个拍卖时,第一个子进程将继续执行,而第二个子进程将停止并等待另一个子进程完成,然后再继续执行(在本例中将 PID 保存在 mnesia 上)。 代码并没有在保存部分停止,因为甚至没有显示auction_handle函数的第一个日志打印:

(

logger:debug("[erws_auction_handler] auction_handle => Auction process started
).

问题可能是什么?我想过使用 gproc 映射拍卖进程的 PID,就像我为用户订阅有关价格的通知一样,但我不知道这是否可以解决问题,因为该进程根本没有开始执行。

concurrency functional-programming erlang erlang-otp erlang-supervisor
1个回答
0
投票

问题是,主管子规范中的

start
函数应该生成一个新进程并返回
{ok, Pid}
-
supervisor
模块不会为您生成该进程。它只是等待启动函数返回。

因此将子规范更改为:

        #{
            id => erws_auction_handler,
            start => {erws_auction_handler, start_link, []},

并添加

erws_auction_handler:start_link/4
功能:

start_link(Phone, Bid, AuctionTime, EndDate) ->
    Pid = spawn_link(?MODULE, auction_handle, [Phone, Bid, AuctionTime, EndDate]),
    {ok, Pid}.

(别忘了导出

start_link/4
!)


您可以做的另一件事是更改

erws_auction_handler
模块以遵循 gen_server 行为。在这种情况下,
erws_auction_handler:start_link
函数只会调用
gen_server:start_link
,并且传入消息将通过
handle_info
回调函数而不是通过
receive
表达式接收。

© www.soinside.com 2019 - 2024. All rights reserved.