Erlang: starting gen_server on another node fails after init - erlang

I am stuck in a bit of a fix trying to run gen_server on another node. So I have a common gen_server class which looks like this
start(FileName) ->
start_link(node(), FileName).
start_link(ThisNode, FileName) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [ThisNode, FileName], []).
init([ThisNode, FileName]) ->
process_flag(trap_exit, true),
{ok, Terms} = file:consult(FileName),
{A1, B1, C1} = lists:nth(1,Terms),
place_objects(A1, B1, C1).
Now I want to start multiple nodes that will run the same gen_server and somehow communicate with each other, and use a another node to orchestrate that. (All these nodes are started on my local terminal).
So I start a new node in one terminal using erl -sname bar where I intend to run the gen_server, and compile the gen_server module on this node. Then I start another node called 'sup' which I intend to use as a coordinator for all the other nodes. If I run the command my_gen_server:start("config_bar.txt"). on bar, it successfully returns but when I run the command rpc:call('bar#My-MacBook-Pro', my_gen_server, start, ["config_bar.txt"]). on sup, it successfully returns from the init method (I checked this by putting in the logs) but immediately after that, I get this error:
{ok,<9098.166.0>}
(sup#My-MacBook-Pro)2> =ERROR REPORT==== 21-Feb-2022::11:12:30.443051 ===
** Generic server my_gen_server terminating
** Last message in was {'EXIT',<9098.165.0>,
{#Ref<0.3564861827.2990800899.137513>,return,
{ok,<9098.166.0>}}}
** When Server state == {10,10,#Ref<9098.1313723616.3973185546.82660>,
'bar#My-MacBook-Pro'}
** Reason for termination ==
** {#Ref<0.3564861827.2990800899.137513>,return,{ok,<9098.166.0>}}
=CRASH REPORT==== 21-Feb-2022::11:12:30.443074 ===
crasher:
initial call: my_gen_server:init/1
pid: <9098.166.0>
registered_name: my_gen_server
exception exit: {#Ref<0.3564861827.2990800899.137513>,return,
{ok,<9098.166.0>}}
in function gen_server:decode_msg/9 (gen_server.erl, line 481)
ancestors: [<9098.165.0>]
message_queue_len: 0
messages: []
links: []
dictionary: []
trap_exit: true
status: running
heap_size: 1598
stack_size: 29
reductions: 3483
neighbours:
I can't seem to figure out what causes the error and if there's anything I need to add to my gen_server code to fix it. Would really appreciate some help on this one!

The gen_server in the remote node is linked to an ephemeral process created for the rpc call.
As this ephemeral process exits with a term that's different from normal (the actual result of the rpc call), the exit signal propagates to the gen_server, killing it.
You can use gen_server:start instead of gen_server:start_link or, if you want the gen_server to be part of the supervission tree, instruct its supervisor to spawn it:
rpc:call('bar#My-MacBook-Pro', my_gen_sup, start_child, ["config_bar.txt"]).

Related

Erlang/Yaws: Cannot start web server within application using .conf file

I'm kind of at a loss. YAWS works fine starting as a service during boot in LXQt 19.04. But I intended on using a rate limiter; setting it in arg_rewrite_mod. Having one VM run YAWS and another my application, setting code paths appropriately, I believe would yield subpar performance because the rate limiting calls would use OS-based IPC and not Erlang IPC. Hence there should be OS IPC overhead and not EVM overhead, correct?
I basically just wanted everything under one hood to eliminate that. This is one thing were there are probably a few ways to approach the problem (i.e. split up my project and duplicate pieces where needed) but I like the "simplicity" of everything in one place.
I'm getting an error, {badmatch, {error, enoent}}, in the shell after:
code:add_patha("/usr/lib/yaws/ebin").
application:start(yaws).
It is occurring on line 548 in yaws_server:setup_dirs/1 (Github)
setup_dirs(GC) ->
Dir = yaws:id_dir(GC#gconf.id),
Ctl = yaws:ctl_file(GC#gconf.id),
ok = filelib:ensure_dir(Ctl),
case file:list_dir(Dir) of
{ok, LL} ->
lists:foreach(
fun(F) ->
file:delete(filename:join([Dir, F]))
end, LL -- ["CTL"]); %%% <---- LINE 548
{error, RSN} ->
error_logger:format("Failed to list ~p probably "
"due to permission errs: ~p",
[Dir, RSN]),
erlang:error(RSN)
end.
I made a UNIX group appname consisting of myself and the user yaws. I've gone around to various directories I found with sudo find / -group yaws -type d and set group permissions to the same as owner as well as reassigning the group from yaws to appname.... I believe since I did not set the id it is "default". My logs (/var/log/yaws/report.log) I was hoping would indicate the problem. They are empty.
I'm essentially using the default /etc/yaws/yaws.conf file. The server section has been removed and placed in /etc/yaws/conf.avail/ with a symlink in /etc/yaws/conf.d/.
UPDATE: The crash report ----
2020-03-27T08:30:04.131073-05:00 notice: Yaws: Using config file /etc/yaws/yaws.conf
2020-03-27T08:30:04.136142-05:00 error: use_old_ssl in yaws.conf is no longer supported - ignoring
2020-03-27T08:30:04.137441-05:00 notice: Yaws: Using global subconfig file /etc/yaws/conf.d/localhost.conf
2020-03-27T08:30:04.140979-05:00 error:
crasher:
initial call: yaws_server:init/1,
pid: <0.114.0>,
registered_name: [],
error: {{badmatch,{error,enoent}},
[{yaws_server,setup_dirs,1,[{file,"yaws_server.erl"},{line,548}]},
{yaws_server,init2,5,[{file,"yaws_server.erl"},{line,224}]},
{gen_server,init_it,2,[{file,"gen_server.erl"},{line,374}]},
{gen_server,init_it,6,[{file,"gen_server.erl"},{line,342}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,249}]}]},
ancestors: [yaws_sup,<0.108.0>],
message_queue_len: 0,
messages: [],
links: [<0.109.0>,#Port<0.6>],
dictionary: [{gc,{gconf,"/usr/lib/yaws",false,612,"/var/log/yaws",
["/usr/local/lib/yaws-appmods/ebin","/usr/lib/yaws/examples/ebin"],
[],[],30000,nolimit,400,1000000,8000,nolimit,[],10240,[],0,30,
["/usr/local/lib/yaws-appmods/include","/usr/lib/yaws/examples/include"],
"/usr/bin/php-cgi","Yaws 2.0.6","default",false,[],8,undefined,
[inet],yaws_session_server,undefined,120000,3600000,disable}},
{start_time,{{2020,3,27},{8,30,4}}}],
trap_exit: true,
status: running,
heap_size: 1598,
stack_size: 27,
reductions: 32410;
neighbours:
2020-03-27T08:30:04.141195-05:00 error:
supervisor: {local,yaws_sup},
errorContext: start_error,
reason: {{badmatch,{error,enoent}},
[{yaws_server,setup_dirs,1,[{file,"yaws_server.erl"},{line,548}]},
{yaws_server,init2,5,[{file,"yaws_server.erl"},{line,224}]},
{gen_server,init_it,2,[{file,"gen_server.erl"},{line,374}]},
{gen_server,init_it,6,[{file,"gen_server.erl"},{line,342}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,249}]}]},
offender: [{pid,undefined},
{id,yaws_server},
{mfargs,
{yaws_server,start_link,
[{env,false,false,false,false,false,false,"default",latin1}]}},
{restart_type,permanent},
{shutdown,120000},
{child_type,worker}]
2020-03-27T08:30:04.145621-05:00 error:
crasher:
initial call: application_master:init/4,
pid: <0.107.0>,
registered_name: [],
exit: {{{shutdown,{failed_to_start_child,yaws_server,{{badmatch,{error,enoent}},
[{yaws_server,setup_dirs,1,[{file,"yaws_server.erl"},{line,548}]},
{yaws_server,init2,5,[{file,"yaws_server.erl"},{line,224}]},
{gen_server,init_it,2,[{file,"gen_server.erl"},{line,374}]},
{gen_server,init_it,6,[{file,"gen_server.erl"},{line,342}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,249}]}]}}},
{yaws_app,start,[normal,[]]}},
[{application_master,init,4,[{file,"application_master.erl"},{line,138}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,249}]}]},
ancestors: [<0.106.0>],
message_queue_len: 1,
messages: [{'EXIT',<0.108.0>,normal}],
links: [<0.106.0>,<0.43.0>],
dictionary: [],
trap_exit: true,
status: running,
heap_size: 987,
stack_size: 27,
reductions: 225;
neighbours:
2020-03-27T08:30:04.147171-05:00 notice:
application: yaws,
exited: {{shutdown,{failed_to_start_child,yaws_server,{{badmatch,{error,enoent}},
[{yaws_server,setup_dirs,1,[{file,"yaws_server.erl"},{line,548}]},
{yaws_server,init2,5,[{file,"yaws_server.erl"},{line,224}]},
{gen_server,init_it,2,[{file,"gen_server.erl"},{line,374}]},
{gen_server,init_it,6,[{file,"gen_server.erl"},{line,342}]},
{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},
{line,249}]}]}}},{yaws_app,start,[normal,[]]}},
type: temporary
SOLUTION:
From the help from the answer below and from having explored the various YAWS paths using find above I found the "default" home directory for me was `/var/cache/yaws/'. The following series of commands in the shell worked for me:
os:putenv("YAWSHOME","/var/cache/yaws/").
code:add_patha("/usr/lib/yaws/ebin").
application:start(yaws).
The source code line 548 shown in your question can't return {error, enoent}, but line 548 of yaws_server.erl for version 2.0.6 is
ok = filelib:ensure_dir(Ctl),
and this is what's returning the error tuple, which fails to match the expected atom ok and causes the failure.
The function filelib:ensure_dir/1 verifies that the parent directories of its argument exist, attempting to create them if they don't. Solving this problem therefore requires determining the Ctl argument pathname in the code shown above.
Since your server id is "default", Ctl in this case is defined as the path
<HOME>/.yaws/yaws/default/CTL
where <HOME> comes either from the setting for the YAWSHOME environment variable if it exists, otherwise from the setting for the HOME environment variable. Make sure one of these environment variables is set to a suitable path and that the .yaws/yaws/default subdirectory under it, if already present, has the appropriate permissions for your yaws user id and appname group id.

Call Python function from Erlang Code

I am working on MQTT broker (http://www.emqtt.io), which is written in Erlang. I have a use case where I need to call one of my python module from emqtt broker code written in erlang.
I have already checked into the google about erlport (http://erlport.org/) which is use for port communication between erlang and python. It works well in erlang shell but when I use the same in emqtt erlang code then it does not work. It throws an error shown below
17:22:40.073 <0.717.0> [error] gen_server <0.717.0> terminated with reason: call to undefined function python:start()
17:22:40.073 <0.717.0> [error] CRASH REPORT Process <0.717.0> with 1 neighbours exited with reason: call to undefined function python:start() in gen_server2:terminate/3 line 1151
17:22:40.073 <0.631.0> [error] Supervisor emqttd_session_sup had child session started with {emqttd_session,start_link,undefined} at <0.717.0> exit with reason call to undefined function python:start() in context child_terminated
17:22:40.073 <0.677.0> [error] Supervisor 'esockd_connection_sup - <0.677.0>' had child connection started with emqttd_client:start_link([{packet,[{max_clientid_len,512},{max_packet_size,65536}]},{client,[{idle_timeout,30}]},{session,...},...]) at <0.716.0> exit with reason call to undefined function python:start() in context connection_crashed
We are calling python module from emqtt plugins code, change of code is show below
on_message_acked(ClientId, Message, _Env) ->
io:format("client ~s acked: ~s~n", [ClientId, emqttd_message:format(Message)]),
io:format("client ~s",[python:start()]),
{ok, Message}.
Please help us.

Can't start supervisor from yaws runmod

I have a yaws runmod defined in yaws.conf as:
runmod = sg_app
the module contains an exported function:
start()->
io:format("~p start~n", [ sg_sup:start_link() ]).
When I start yaws I see a call to the runmod:
=INFO REPORT==== 29-Oct-2015::16:46:51 === sync call sg_app:start
{ok,<0.61.0>} start
But the supervisor is nonexistent:
1> whereis(sg_sup).
undefined
If I call the runmod:start manually, the supervisor hangs around.
2> sg_app:start().
{ok,<0.73.0>} start
ok
3> whereis(sg_sup).
<0.73.0>
What have I done wrong?
Your runmod's start/0 function is starting the supervisor with start_link/0, which means it's getting linked to the parent process. When that process dies, it takes your runmod process down with it, due to the link. The runmod feature isn't designed for starting a supervision tree.
You might instead consider using a yapp, which allows your code to run as a regular Erlang application in the same Erlang node as Yaws and be registered to have Yaws dispatch requests into it.
Another option is to launch your application using a separately spawned, infinite process:
start()->
spawn(fun () ->
application:start(my_app, permanent),
receive after infinity -> ok end
end).

ERROR REPORT Generic server <0.35.0> terminating Last message in was {req_timeout,#Ref<0.0.0.60>}

I am going through the riak-erlang-client https://github.com/basho/riak-erlang-client. As i am following the steps, i am facing error at storing the data.
I did the following:
2> {ok,Pid} = riakc_pb_socket:start_link("127.0.0.1",8087).
{ok,<0.35.0>}
3>
3>
3> riakc_pb_socket:ping(Pid).
pong
4> Val = 1.
1
7> Obj = riakc_obj:new(<<"Bucket">>,<<"one">>,Val).
{riakc_obj,<<"Bucket">>,<<"one">>,undefined,[],undefined,1}
everything was working here as per the documents, but when i am trying to store the data with the following command.
8> riakc_pb_socket:put(Pid,Obj).
After this command i am getting the following error,
=ERROR REPORT==== 13-May-2014::18:15:46 ===
** Generic server <0.35.0> terminating
** Last message in was {req_timeout,#Ref<0.0.0.60>}
** When Server state == {state,"127.0.0.1",8087,false,false,undefined,false,
gen_tcp,undefined,
{[],[]},
1,[],infinity,undefined,undefined,undefined,
undefined,[],100}
** Reason for termination ==
** disconnected
** exception exit: disconnected
where i am doing wrong, please suggest me.
That error means that your TCP request timed out for some reason. Is there anything in Riak's error.log or console.log files that could tell you why?
Can you test to see if your Riak node is running by going to http:127.0.0.1:8098/ping in a browser?
If it's up and running you can try your test again by either clearing your currently bound variables with f(). (or opening a new Erlang REPL), and retrying the commands.

How to always log/show the error reason when a supervisor child returns error from start_link?

When starting gen_server's from a supervisor (which itself is started by a application) I have the problem that when the start_link of the gen_server doesn't return {ok, ...} but {error, Reason} the only error message I see is:
=INFO REPORT==== 20-Jan-2011::13:14:43 ===
application: foo
exited: {shutdown,{foo_app,start,[normal,[]]}}
type: temporary
The Reason that for terminating is not shown/logged.
Is there a way to see/log these error returns to the supervisor?
The childspec I'm using is e.g.:
{ok, {{one_for_one, 3, 10}, ...
{usb_mux_1,
{usb_mux, start_link,
[Some_Params]},
permanent,
10000,
worker,
[usb_mux]}, ...
Edit: Clarification
I know about error_logger and using it already. The question is not how to get something logged but how to get supervisor to log the reason for it terminating, e.g. log who terminated with an error return and what did it return.
And just to get this also out of the way, yes I start erlang with sasl on:
-boot start_sasl
Just discovered the answer myself:
The supervisor is really logging the error exit as crash report.
The problem is the shell doesn't show these crash reports. Just to confuse me it shows info/warning and error reports but no progess reports and crash reports from the supervisor.
If I look in the on disk log there is a detailed crash report there:
10> rb:show(4).
CRASH REPORT <0.53.0> 2011-01-20 17:33:52
===============================================================================
Crashing process
initial_call {usb_mux,init,['Argument__1']}
pid <0.53.0>
registered_name []
error_info
{exit,{undef,[{usb_port,get_gw_hw_spec,[<0.59.0>]},
...
The reason the SASL events were not shown on the screen was a ommission in the -config file, which looked like this:
[{sasl, [
{sasl_error_logger, false}, %% no SASL error logger installed
{error_logger_mf_dir,"./log"},
{error_logger_mf_maxbytes,10485760}, % 10 MB
{error_logger_mf_maxfiles, 10}
]}].
Meaning there was a multi-file erroro logger installen (all the error_logger_mf_* entries) but no on screen logger for SASL events.
Changing the entry like this fixed it:
{sasl_error_logger, tty}, %% SASL reports to tty
From the sasl manpage:
sasl_report_tty_h:
Formats and writes supervisor reports, crash reports and progress reports to stdio .

Resources