functional-programmingerlangdistributed-computingerlang-otperlang-supervisor

Error: invalid child spec in supervisor start_child function


In my erlang application i have a top level supervisor that monitors a cowboy server (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}}.` 

The requests to the server can trigger the call of functions from another module, called erws_auction_agent. Inside this module, when a certain request is received, it executes the spawn of a new process that has to handle the request (an auction in this case):

AuctionPid = spawn(fun() -> auction_handle(PhoneName, MinimumPrice, AuctionTime, EndDate) end)

The auction_handle function has to basically wait for erlang messages and perform different operations depending on the message:

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.

I thought that could be a good idea to have a supervisor also for these processes, that are added dynamically. I tried both adding them to the already present supervisor and creating another supervisor started from the higher level one, but got the same error, related to child specification. For instance, i tried adding the child to the top level supervisor by calling this function from it:

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.

The error I get is the following:

{error,
{invalid_child_spec,
[#{id => <<"Sony Xperia Pro">>, restart => transient,
start =>
{erws_auction_agent,auction_handle,
[<<"Sony Xperia Pro">>, 1, 240,
1714667160]}}]}}

What am I doing wrong? Which can be the best approach to use in this case? Do i need to have a separate gen_server for the handle_auction logic? Thanks in advance.


Solution

  • supervisor:start_child/2 is defined like so:

    start_child(SupRef, ChildSpec) -> startchild_ret()
    

    where ChildSpec is of type:

    child_spec() | (List :: [term()])
    

    And child_spec() is defined to be:

       #{stuff in here} OR {stuff in here}
    

    All together, ChildSpec can be:

    #{stuff in here} OR {stuff in here} OR [stuff in here]
    

    Instead of this:

    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}]),
       
    

    try:

    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
                 }
        ),