我正在编写一个简单的 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,就像我为用户订阅有关价格的通知一样,但我不知道这是否可以解决问题,因为该进程根本没有开始执行。
问题是,主管子规范中的
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
表达式接收。