4

我是 Erlang 的新手,想将 bash 脚本与 Erlang 节点和函数合并。我有一个 Mnesia 数据库,我们进入 Erlang 节点并运行几个函数,但我想通过一些 bash 脚本运行这些函数,以便我可以在其他地方使用这些 bash 脚本输出。我的二郎壳:-

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> 

在这个 shell 中,当我们运行下面的函数时,它运行良好并给出输出,请注意 order_node、pps_manager 是数据库中的模块名称,get_by_id、send_order_related_notification、update_status_of_order_node 是该模块中的函数。

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().

请让我知道如何使用 bash 脚本在 erlang shell 中运行上面的代码片段。

4

1 回答 1

4

当你使用 escript 时,你启动了一个新的 Erlang VM,所以如果你想真正连接到一个正在运行的节点,你需要使用类似expect的东西。

但是,您可以使用 escript 启动一个新节点并将其添加到正在运行的集群中,并且借助rpc 模块中的方法,您可以在原始集群中运行代码:

假设您有一个以 开头的节点erl -name main@127.0.0.1 -setcookie cookie,然后是 escript

#!/usr/bin/env escript
%%! -name escript@127.0.0.1 -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.

将打印

$> ./test.escript main@127.0.0.1
Escript node: 'escript@127.0.0.1'
'main@127.0.0.1''s node(): 'main@127.0.0.1'
'main@127.0.0.1''s nodes(): []

(请注意,由于-hidden 标志,main 的节点列表是空的)。

除了他的 escript 没有运行任何有用的代码这一事实之外,这里还有三个问题:

1
escript节点名称:由于erlang集群或同一主机中的名称必须是唯一的,如果escript有可能同时运行两次,这可能是一个问题。您可以通过生成一个随机名称来解决它(在 Erlang 或 bash 中,示例适用于 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 main@127.0.0.1 
Escript node: 'escript45560706@127.0.0.1'
'main@127.0.0.1''s node(): 'main@127.0.0.1'
'main@127.0.0.1''s nodes(): []
'main@127.0.0.1''s nodes(hidden): ['escript45560706@127.0.0.1']

但是,escript 节点的名称是一个原子,原子没有被 GC 处理,并且原子限制虽然非常高,但仍然存在。根据您的配置和使用模式,这对您来说可能是也可能不是问题。

2
原始节点名称和cookie:要连接到main@127.0.0.1您需要知道名称,是否以长名称或短名称开头(如果主机部分有一个点,您需要长名称)和cookie。此信息在vm.args文件中(或在 shell 行中)。
如果没有设置 cookie,Erlang 会创建一个随机的 cookie 并将其放在$HOME.

3
与原始节点的网络连接:Erlang 分布式协议要求 4369 端口(用于EPMD)和节点范围(可用于配置inet_dist_listen_mininet_dist_listen_max)可达。

准备好 escript 后,您可以从 bash 脚本调用它,也可以在调用它之前从 bash 脚本将其写入临时文件env escriptbash 进程替换不起作用,因为 escript 使用file:position并且进程替换是管道)。

于 2020-05-26T20:18:33.440 回答