Erlang and bash scripting (escript)

1.1k views Asked by At

I am very new in Erlang and want to merge bash script with Erlang node and function. I have one Mnesia Database where we go into Erlang node and run several function but i want to run those functions via some bash script so that I can use those bash script output elsewhere. My Erlang shell:-

sudo /opt/butler_server/bin/butler_server remote_console
Erlang/OTP 20 [erts-9.3.3.6] [source] [64-bit] [smp:28:28] [ds:28:28:10] [async-threads:10] 

Eshell V9.3.3.6  (abort with ^G)
(butler_server@localhost)1> 

And inside this shell when we run below function its running fine and giving output also, Please note order_node, pps_manager are the module name in the Database and get_by_id,send_order_related_notification,update_status_of_order_node are the fuction in that module.

f().

ChangeStatus =
fun() ->
        {ok,C2}=order_node:search_by([{status,equal,inventory_awaited}],key),

        io:format("Total Orders ~p", [length(C2)]),

        lists:foreach(fun(Id) ->
                              io:format("Orders ~p~n", [Id]),
                              order_node:update_status_of_order_node(Id,cancelled),
                              pps_manager:send_order_related_notification(element(2,order_node:get_by_id(Id)))
                      end, C2)
end.

ChangeStatus().

Please let me know how i can run above code snippet in erlang shell by using a bash script.

1

There are 1 answers

0
José M On

When you use escript, you start a new Erlang VM, so if you want to really connect to a running node, you need to use something like expect.

However, with escript you can start a new node and add it to a running cluster, and with the help of the methods in the rpc module you can run code in the original cluster:

Let's say that you have a node started with erl -name [email protected] -setcookie cookie, then the escript

#!/usr/bin/env escript
%%! -name [email protected] -hidden -setcookie cookie
main([RemoteNodeString]) ->
    io:format("Escript node: ~p~n", [node()]),
    RemoteNode = list_to_atom(RemoteNodeString),
    io:format("~p's node(): ~p~n", [RemoteNode, rpc:call(RemoteNode, erlang, node, [])]),
    io:format("~p's nodes(): ~p~n", [RemoteNode, rpc:call(RemoteNode, erlang, nodes, [])]),
    ok.

will print

$> ./test.escript [email protected]
Escript node: '[email protected]'
'[email protected]''s node(): '[email protected]'
'[email protected]''s nodes(): []

(Notice that main's nodes list is empty thanks to the -hidden flag).

Aside from the fact that his escript is not running any useful code, there are three issues here:

1
escript node name: As names in the erlang cluster or in the same host must be unique, this may be a problem if there's a chance that the escript is run twice concurrently. You can solve it by generating a random name (in Erlang or bash, the example is for Erlang):

#!/usr/bin/env escript
%%! -hidden -setcookie cookie
main([RemoteNodeString]) ->
    RandomTail = (<< <<($0 + rand:uniform(10)-1)>> || _ <- lists:seq(1,8) >>),
    RandomName = binary_to_atom(<<"escript", RandomTail/binary, "@127.0.0.1">>, utf8),
    io:format("Escript node: ~p~n", [RandomName]),
    net_kernel:start([RandomName, longnames]),
    RemoteNode = list_to_atom(RemoteNodeString),
    io:format("~p's node(): ~p~n", [RemoteNode, rpc:call(RemoteNode, erlang, node, [])]),
    io:format("~p's nodes(): ~p~n", [RemoteNode, rpc:call(RemoteNode, erlang, nodes, [])]),
    io:format("~p's nodes(hidden): ~p~n", [RemoteNode, rpc:call(RemoteNode, erlang, nodes, [hidden])]),
    ok.

$> ./test2.escript [email protected] 
Escript node: '[email protected]'
'[email protected]''s node(): '[email protected]'
'[email protected]''s nodes(): []
'[email protected]''s nodes(hidden): ['[email protected]']

However, the escript node's name is an atom, atoms are not GC'd and the atoms limit, although really high, is present. It may or may not be an issue for you depending on your configuration and your use pattern.

2
Original node name and cookie: To connect to [email protected] you need to know the name, if it was started with long or short names (if the host part has a dot, you need longnames) and the cookie. This information is in the vm.args file (or in the shell line).
If no cookie was set, Erlang creates a random one and places it in the $HOME.

3
Network connection to the original node: Erlang distributed protocol requires the 4369 port (for EPMD) and a range for the nodes (avaliable for configuration with inet_dist_listen_min and inet_dist_listen_max) reachable.

Once you have the escript ready, you can call it from your bash script or you can write it to a tempfile from your bash script before calling env escript on it (bash process substitution does not work because escript uses file:position and the process substitution is a pipe).