Erlang supervisor exception on starting worker - exception
I'm playing with code for supervisor trees taken from http://learnyousomeerlang.com/building-applications-with-otp but I get a noproc exception that I can't figure out when I try to get a supervisor to start the child process. This is my shell interaction:
1> application:start(test).
root supervisor init
ok
2> test_sup:start_service(service_sup,{service_worker, start_link,[]}).
{ok,<0.39.0>}
worker supervisor initialise (M: service_worker,F: start_link,A: [])
3> test_app:run(service_worker,[]).
server run: (name: service_worker args: [])
** exception exit: {noproc,{gen_server,call,[service_worker,{run,[]}]}}
in function gen_server:call/2 (gen_server.erl, line 182)
Code is:
-module(test_app).
-behaviour(application).
-export([start/2, stop/1, run/2]).
start(_StartType, _StartArgs) ->
test_sup:start_link().
run(Name, Args) ->
service_serv:run(Name, Args).
=====
-module(test_sup).
-behaviour(supervisor).
-export([start_link/0, init/1, stop/0, start_service/2, stop_service/1]).
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
start_link() ->
supervisor:start_link({local, service}, ?MODULE, []).
init([]) ->
io:format("root supervisor init~n"),
{ok, {{one_for_one, 5, 10},
[]}}.
start_service(Name, MFA) ->
ChildSpec = {Name,
{service_sup, start_link, [Name, MFA]},
permanent, 10500, supervisor, [service_sup]},
io:format("start service supervisor (Name: ~p, MFA: ~p): ", [Name, MFA]),
supervisor:start_child(service, ChildSpec).
[snip]
====
-module(service_sup).
-export([start_link/2, init/1]).
-behaviour(supervisor).
start_link(Name, MFA) ->
supervisor:start_link(?MODULE, {Name, MFA}).
init({Name, MFA}) ->
MaxRestart = 1,
MaxTime = 3600,
{ok, {{one_for_all, MaxRestart, MaxTime},
[{serv,
{service_serv, start_link, [Name, self(), MFA]},
permanent,
5000,
worker, [service_serv]}]}}.
========
-module(worker_sup).
-export([start_link/1, init/1]).
-behaviour(supervisor).
start_link(MFA) ->
supervisor:start_link(?MODULE, MFA).
init({M,F,A}) ->
{ok, {{simple_one_for_one, 5, 3600},
[{service_worker,
{M,F,A},
temporary, 5000, worker, [M]}]}}.
===
-module(service_serv).
-behaviour(gen_server).
-export([start/3, start_link/3, run/2,
status/1, ping/1, stop/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
code_change/3, terminate/2]).
-define(WORKER_SUP_SPEC(MFA),
{worker_sup,
{worker_sup, start_link, [MFA]},
permanent,
10000,
supervisor,
[worker_sup]}).
-record(state, {sup,
refs,
queue=queue:new()
}).
start(Name, Sup, MFA) when is_atom(Name) ->
gen_server:start({local, Name}, ?MODULE, {MFA, Sup}, []).
start_link(Name, Sup, MFA) when is_atom(Name) ->
gen_server:start_link({local, Name}, ?MODULE, {MFA, Sup}, []).
init({MFA, Sup}) ->
self() ! {start_worker_supervisor, Sup, MFA},
{ok, #state{}}.
run(Name, Args) ->
io:format("server run: (name: ~p args: ~p) ~n",[Name, Args]),
gen_server:call(Name, {run, Args}).
handle_info({start_worker_supervisor, Sup, MFA}, S = #state{}) ->
{ok, Pid} = supervisor:start_child(Sup, ?WORKER_SUP_SPEC(MFA)),
{noreply, S#state{sup=Pid}};
handle_info({'DOWN', Ref, process, _Pid, _}, S = #state{refs=Refs}) ->
case gb_sets:is_element(Ref, Refs) of
true ->
handle_down_worker(Ref, S);
false -> %% Not our responsibility
{noreply, S}
end;
handle_info(Msg, State) ->
{noreply, State}.
handle_call({run, Args}, _From, S = #state{sup=Sup, refs=R}) ->
io:format("handle run call ~n"),
{ok, Pid} = supervisor:start_child(Sup, Args),
Ref = erlang:monitor(process, Pid),
{reply, {ok, run, Pid}, S#state{refs=gb_sets:add(Ref,R)}};
[snip]
====
-module(service_worker).
-behaviour(gen_server).
-export([start_link/4, stop/1]).
-export([init/0, init/1, handle_call/3, handle_cast/2,
handle_info/2, code_change/3, terminate/2]).
start_link(Task, Delay, Max, SendTo) ->
gen_server:start_link(?MODULE, {Task, Delay, Max, SendTo} , []).
stop(Pid) ->
gen_server:call(Pid, stop).
init({Task, Delay, Max, SendTo}) ->
io:format("initialise worker ~n"),
%% {ok, {Task, Delay, Max, SendTo}}.
{ok, {Task, Delay, Max, SendTo}, Delay}.
[snip]
The volume of code you've produced is a little difficult to parse, but what stands out to me most is that you are apparently using the atom "service_worker" to refer to the process that you start.
This is all well and good if you register a process with that atom (either by calling erlang:register(service_worker, Pid) or starting the process with gen_server:start_link({local, service_worker}, ?MODULE, Args, Opts)). You appear to be doing neither, and the error message you receive supports that assessment.
** exception exit: {noproc,{gen_server,call,[service_worker,{run,[]}]}}
in function gen_server:call/2 (gen_server.erl, line 182)
What this error tells us is that gen_server:call was not able to find the process (noproc). The arguments to gen_server:call are included in the error message, and in the spot where one would expect to find the Pid, we find instead service_worker.
Additionally, your service_worker module appears to be started by a simple_one_for_one supervisor. Such supervisors are used when you need multiple of the same "type" of process (e.g., same callback module). Such supervisors also do not start workers on their own (you must invoke supervisor:start_child(SupPid, ExtraArgs)).
Those are the two main issues I see with your present attempt. For a quick and dirty fix, try adding {local, service_worker} or {local, ?MODULE} as the first argument to the gen_server:start_link call in the service_worker module. Please bear in mind that this will not work if you intend to start multiple service_worker processes (as only one process can be registered to an atom at a time).
Related
Beginner in Elixir : parse CSV file
Hello I'm a beginner in Elixir and I want to parse and stock a CSV file in an Elixir object. But it's display that: ** (FunctionClauseError) no function clause matching in anonymous fn/1 in Siren.parseCSV/0 The following arguments were given to anonymous fn/1 in Siren.parseCSV/0: # 1 ["41", "5", "59", "N", "80", "39", "0", "W", "Youngstown", "OH"] anonymous fn/1 in Siren.parseCSV/0 (elixir 1.10.3) lib/stream.ex:482: anonymous fn/4 in Stream.filter/2 (elixir 1.10.3) lib/stream.ex:1449: Stream.do_element_resource/6 (elixir 1.10.3) lib/stream.ex:1609: Enumerable.Stream.do_each/4 (elixir 1.10.3) lib/enum.ex:959: Enum.find/3 (mix 1.10.3) lib/mix/task.ex:330: Mix.Task.run_task/3 (mix 1.10.3) lib/mix/cli.ex:82: Mix.CLI.run_task/2 Here my code: defmodule Siren do def parseCSV do IO.puts("Let's parse CSV file...") File.stream!("../name.csv") |> Stream.map(&String.trim(&1)) |> Stream.map(&String.split(&1, ",")) |> Stream.filter(fn ["LatD" | _] -> false end) |> Enum.find(fn State -> String [LatD, LatM, LatS, NS, LonD, LonM, LonS, EW, City, State] -> IO.puts("find -> #{State}") true end) end end And the csv file: LatD,LatM,LatS,NS,LonD,LonM,LonS,EW,City,State 41,5,59,N,80,39,0,W,Youngstown,OH 42,52,48,N,97,23,23,W,Yankton,SD 46,35,59,N,120,30,36,W,Yakima,WA 42,16,12,N,71,48,0,W,Worcester,MA 43,37,48,N,89,46,11,W,WisconsinDells,WI 36,5,59,N,80,15,0,W,Winston-Salem,NC 49,52,48,N,97,9,0,W,Winnipeg,MB 39,11,23,N,78,9,36,W,Winchester,VA 34,14,24,N,77,55,11,W,Wilmington,NC 39,45,0,N,75,33,0,W,Wilmington,DE 48,9,0,N,103,37,12,W,Williston,ND 41,15,0,N,77,0,0,W,Williamsport,PA 37,40,48,N,82,16,47,W,Williamson,WV 33,54,0,N,98,29,23,W,WichitaFalls,TX 37,41,23,N,97,20,23,W,Wichita,KS 40,4,11,N,80,43,12,W,Wheeling,WV 26,43,11,N,80,3,0,W,WestPalmBeach,FL 47,25,11,N,120,19,11,W,Wenatchee,WA 41,25,11,N,122,23,23,W,Weed,CA
The first issue is here: |> Stream.filter(fn ["LatD" | _] -> false end) all the lines should pass this and the only first one matches the given clauses. This would fix the issue |> Stream.filter(fn ["LatD" | _] -> false _ -> true end) or |> Stream.reject(&match?(["LatD" | _], &1)) Enum.find(fn State -> String after looks unclear and would be surely the next issue. I failed to understand what have you tried to achieve here. The general advice would be: don’t reinvent the wheel and use NimbleCSV written by José Valim to parse CSVs, because there are lot of corner cases (like commas inside quotes in any field etc,) handled properly in the aforementioned library.
Aleksei Matiushkin gave you the right answer but also you have this function: fn State -> String [LatD, LatM, LatS, NS, LonD, LonM, LonS, EW, City, State] -> IO.puts("find -> #{State}") true end It accepts two possible values, either State which is an atom, or a list of 10 specific atoms. What you want to do is use variables, and variables in Elixir start with a lowercase letter or an underscore if it has to be ignored. fn state -> String [latd, latm, lats, ns, lond, lonm, lons, ew, city, state] -> IO.puts("find -> #{state}") true end But in this case, the first clause of the function will always match anything because it acts like a catch-all clause. What you probably want is: fn [_latd, _latm, _lats, _ns, _lond, _lonm, _lons, _ew, _city, state] -> IO.puts("find -> #{state}") # here decide if you want to return true or false, # for instance `state == NC` true end
GET a URL succeeds in chrome but the get() call never returns
I call .get() on the driver instance with this URL enter link description here and I see in the headful chrome instance that the page loads. However, the .get() call doesn't return after a minute or so. In pdb, I trigger a SIGBREAK and the stack looks like so: -> wdriver.get(url) /usr/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py(326)get() -> self.execute(Command.GET, {'url': url}) /usr/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py(312)execute() -> response = self.command_executor.execute(driver_command, params) /usr/lib/python3.7/site-packages/selenium/webdriver/remote/remote_connection.py(472)execute() -> return self._request(command_info[0], url, body=data) /usr/lib/python3.7/site-packages/selenium/webdriver/remote/remote_connection.py(496)_request() -> resp = self._conn.getresponse() /usr/lib64/python3.7/http/client.py(1336)getresponse() -> response.begin() /usr/lib64/python3.7/http/client.py(306)begin() -> version, status, reason = self._read_status() /usr/lib64/python3.7/http/client.py(267)_read_status() -> line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") /usr/lib64/python3.7/socket.py(589)readinto() -> return self._sock.recv_into(b) Eventually, after 5mns, it timesout: (Session info: headless chrome=75.0.3770.142) (Driver info: chromedriver=75.0.3770.100 (cd0b15c8b6a4e70c44e27f35c37a4029bad3e3b0-refs/branch-heads/3770#{#1033}),platform=Linux 5.2.11-200.fc30.x86_64 x86_64)
How do I get an unhandled exception to be reported in SML/NJ?
I have the following SML program in a file named testexc.sml: structure TestExc : sig val main : (string * string list -> int) end = struct exception OhNoes; fun main(prog_name, args) = ( raise OhNoes ) end I build it with smlnj-110.74 like this: ml-build sources.cm TestExc.main testimg Where sources.cm contains: Group is csx.sml I invoke the program like so (on Mac OS 10.8): sml #SMLload testimg.x86-darwin I expect to see something when I invoke the program, but the only thing I get is a return code of 1: $ sml #SMLload testimg.x86-darwin $ echo $? 1 What gives? Why would SML fail silently on this unhandled exception? Is this behavior normal? Is there some generic handler I can put on main that will print the error that occurred? I realize I can match exception OhNoes, but what about larger programs with exceptions I might not know about?
The answer is to handle the exception, call it e, and print the data using a couple functions available in the system: $ sml Standard ML of New Jersey v110.74 [built: Tue Jan 31 16:23:10 2012] - exnName; val it = fn : exn -> string - exnMessage; val it = fn : exn -> string - Now, we have our modified program, were we have the generic handler tacked on to main(): structure TestExc : sig val main : (string * string list -> int) end = struct exception OhNoes; open List; fun exnToString(e) = List.foldr (op ^) "" ["[", exnName e, " ", exnMessage e, "]"] fun main(prog_name, args) = ( raise OhNoes ) handle e => ( print("Grasshopper disassemble: " ^ exnToString(e)); 42) end I used lists for generating the message, so to make this program build, you'll need a reference to the basis library in sources.cm: Group is $/basis.cm sources.cm And here's what it looks like when we run it: $ sml #SMLload testimg.x86-darwin Grasshopper disassemble: [OhNoes OhNoes (more info unavailable: ExnInfoHook not initialized)] $ echo $? 42 I don't know what ExnInfoHook is, but I see OhNoes, at least. It's too bad the SML compiler didn't add a basic handler for us, so as to print something when there was an unhandled exception in the compiled program. I suspect ml-build would be responsible for that task.
parsing json return from http in erlang
I test with this code : get_fee(Transaction,SourceNumber,Amount, Currency) -> Url = lists:concat(["http://localhost/test.php","?transaction=", Transaction, "&saccount=", SourceNumber,Amount,"¤cy=",Currency]), inets:start(), {Flag, Response} = http:request(get, {Url, []}, [], []), case Flag of ok -> { { _, ReturnCode, _ }, _, Body } = Response, if ReturnCode =:= 200 -> {ok,{_,[{_,Code},{_,Permission},{_,Payer},{_,Payee}]}} = json:decode_string(Body), case Permission of true -> if Code =:= 200 -> {ok,{Code, Payer, Payee}}; Code =:= 204 -> {nok,{Code, not_found}}; true -> {nok,{Code, parameter_error}} end; false -> {nok,{Code, parameter_error}} end; true-> {error, http_error} end; error -> case Response of nxdomain -> {error, dns_error}; _ -> {error, network_error} end end. the response from the http is : {"code":200,"permission":true,"fee_payer":0,"fee_payee":19} But now I like to do the same think but the return of http in this case for example is : {"CIN":"08321224","Name":21} so I have just CIN and Name in this case I try to change the previous get_fee(Num) -> Url = lists:concat(["http://localhost/GTW/Operation.php","?ACCOUNT_NUM=", Num]), inets:start(), {Flag, Response} = http:request(get, {Url, []}, [], []), case Flag of ok -> { { _, ReturnCode, _ }, _, Body } = Response, %% for debug io:format("~p~n",[ReturnCode]), if ReturnCode =:= "08321224" -> {ok,{_,[{_,CIN},{_,Name}]}} = json:decode_string(Body), case Name of 21 -> io:format(CIN), io:format(Name), if CIN =:= "08321224"-> {ok,{CIN, Name}}; CIN =:= 204 -> {nok,{CIN, not_found}}; true -> {nok,{CIN, parameter_error}} end; false -> {nok,{CIN, parameter_error}} end; true-> {error, http_error} end; error -> case Response of nxdomain -> {error, dns_error}; _ -> {error, network_error} %% for debug %%io:format("pass2~n ~p~n",[Response]), end end. but it displys : test:get_fee("0001"). 200 {error,http_error}
So I'll nitpick on the style here, because you will be far better off if you follow the semantical idea of Erlang: get_fee(Num) -> Url = lists:concat(["http://localhost/GTW/Operation.php","?ACCOUNT_NUM=", Num]), inets:start(), This is the wrong place to start inets. It should be started outside this function as you only need to do this one. {Flag, Response} = http:request(get, {Url, []}, [], []), This part is better coded with a pattern match. The discrimination of Flag and Response can be decoded directly with a simple match. Write, case http:request(get, {Url, []}, [], []) of {ok, {{_, 200, _}, _, Body}} -> {ok, R} = json:decode_string(Body), get_fee_decode_(get_cin(R), get_name(R)); {error, Reason} -> {error, Reason} end. I would recommend against changing {error, nxdomain} to {error, dns_error} since nxdomain perfectly codes this case in any case. Just pass the error tuple to the caller and have him handle it. get_fee_decode_("08321224" = CIN, 21 = Name) -> {ok, {CIN, Name}}; get_fee_decode_("204" = CIN, 21) -> {nok, {CIN, not_found}}; get_fee_decode_(CIN, _Name) -> {nok, {CIN, parameter_error}}; Introduce a new function like this to handle the inner parts of your code base. And hoist the matching to top-level. This helps in the long run by decoupling your code into functions. Do note that in a JSON structure, there is no order on an "object" so you can't assume that the structure is {"code":200,"permission":true,"fee_payer":0,"fee_payee":19} But a decode does not have to preserve this structure, according to JSON. So a valid decode may be: [{"fee_payee", 19}, {"fee_payer", 0}, {"permission", true}, {"code", 200}] This will fail to match in your code and you are setting yourself up for some nasty errors later on. You want something along the lines of: get_fee_payer(PL) -> proplists:get_value("fee_payer", PL). Another thing which will be a problem with your programming style is that you are hiding error-information cases. In Erlang, you can often get away with only handling the "happy path" through the code and leave all the error handling out until you know what kind of errors are there in the code base. Then you can begin adding in error handling slowly. Defensive programming is not a thing you should be doing if you can avoid it.
You changed: if ReturnCode =:= 200 -> to: if ReturnCode =:= "08321224" -> However, that needs to stay the same in your version. 200 is the HTTP status code for "OK" - the first step here is to verify that the server actually processed the request and returned a positive reply. You'll find that number only in Body - that is what the if CIN =:= "08321224"-> part is for.
Erlang - undefined function
I'm trying to execute a very simple Erlang code, and it's not working. I've tryied executed some hello worlds without problem, but not mine own code. -module(server). %% Exported Functions -export([start/0, process_requests/1]). %% API Functions start() -> ServerPid = spawn(server, process_requests, [[]]), register(myserver, ServerPid). process_requests(Clients) -> receive {client_join_req, Name, From} -> NewClients = [From|Clients], %% TODO: COMPLETE broadcast(NewClients, {join, Name}), process_requests(NewClients); %% TODO: COMPLETE {client_leave_req, Name, From} -> NewClients = lists:delete(From, Clients), %% TODO: COMPLETE broadcast(Clients, {leave, Name}), %% TODO: COMPLETE process_requests(NewClients); %% TODO: COMPLETE {send, Name, Text} -> broadcast(Clients, {message, Name, Text}), %% TODO: COMPLETE process_requests(Clients) end. %% Local Functions broadcast(PeerList, Message) -> Fun = fun(Peer) -> Peer ! Message end, lists:map(Fun, PeerList). Compile result: 5> c(server). {ok,server} 6> server:start(). ** exception error: undefined function server:start/0
You compile you code with c/1, but you forgot to load it to VM with l/1. While VM does loads modules new automatically (modules not yet loaded to VM), it doesn't reload them each time you compile to new beam. If you do it a lot in development you might want to look into tools like sync.
Try to check with pwd(). whether you are in the directory where your listed server code is. Seems to be a path issue. It also can happen that in your code:get_path() there is a directory where another server.beam is sitting that has not got a start function.