В моем приложении на erlang у меня есть супервизор верхнего уровня, который контролирует ковбойский сервер (gen_server):
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
init([]) ->
SupFlags = #{strategy => one_for_one,
intensity => 5,
period => 30},
ChildSpecs = [#{id => erws_server,
start => {erws_server, start_link, []},
restart => permanent}],
{ok, {SupFlags, ChildSpecs}}.`
Запросы к серверу могут инициировать вызов функций из другого модуля, называемого erws_auction_agent. Внутри этого модуля, когда получен определенный запрос, он запускает новый процесс, который должен обработать запрос (в данном случае аукцион):
AuctionPid = spawn(fun() -> auction_handle(PhoneName, MinimumPrice, AuctionTime, EndDate) end)
Функция Auction_handle должна в основном ожидать сообщений Erlang и выполнять различные операции в зависимости от сообщения:
auction_handle(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.
Я подумал, что было бы неплохо иметь супервизора и для этих процессов, которые добавляются динамически. Я попробовал добавить их к уже существующему супервизору и создать еще один супервизор, начиная с супервизора более высокого уровня, но получил ту же ошибку, связанную со спецификацией дочернего элемента. Например, я попытался добавить дочерний элемент в супервизор верхнего уровня, вызвав из него эту функцию:
start_auction_process(PhoneName, MinimumPrice, AuctionTime, EndDate) ->
{ok, AuctionPid} = supervisor:start_child(?SERVER,
[#{id => PhoneName,
start => {erws_auction_agent, auction_handle, [PhoneName, MinimumPrice, AuctionTime, EndDate]},
restart => transient}]),
AuctionPid.
Я получаю следующую ошибку:
{error,
{invalid_child_spec,
[#{id => <<"Sony Xperia Pro">>, restart => transient,
start =>
{erws_auction_agent,auction_handle,
[<<"Sony Xperia Pro">>, 1, 240,
1714667160]}}]}}
Что я делаю не так? Какой подход лучше всего использовать в этом случае? Нужно ли мне иметь отдельный gen_server для логики handle_auction? Заранее спасибо.
Supervisor:start_child/2 определяется так:
start_child(SupRef, ChildSpec) -> startchild_ret()
где ChildSpec имеет тип:
child_spec() | (List :: [term()])
И child_spec() определяется как:
#{stuff in here} OR {stuff in here}
В целом ChildSpec может быть:
#{stuff in here} OR {stuff in here} OR [stuff in here]
Вместо этого:
start_auction_process(PhoneName, MinimumPrice, AuctionTime, EndDate) ->
{ok, AuctionPid} = supervisor:start_child(?SERVER,
[#{id => PhoneName,
start => {erws_auction_agent, auction_handle, [PhoneName, MinimumPrice, AuctionTime, EndDate]},
restart => transient}]),
пытаться:
start_auction_process(PhoneName, MinimumPrice, AuctionTime, EndDate) ->
{ok, AuctionPid} = supervisor:start_child(
?SERVER,
#{
id => PhoneName,
start => {erws_auction_agent, auction_handle, [PhoneName, MinimumPrice, AuctionTime, EndDate]},
restart => transient
}
),
Спасибо! Это была проблема, которая вызвала ошибку valid_child_spec, я видел (List :: [term()]) в определении start_child/2 и предположил, что это тот же самый вариант, который использовался в функции инициализации супервизора, но это было не так. т. е.