带有启动参数的 Erlang escript 启动应用程序

Erlang escript launching application with start parameters

目前我的 Erlang 应用程序是在 escript(TCP 服务器)中启动的,并且一切正常,因为它使用我提供的默认端口。现在我想通过 escript 将端口传递给应用程序,但我不知道如何。 (该应用程序运行一个主管

script.escript

!/usr/bin/env escript
%% -*- erlang -*-

-export([main/1]).

main([UDPort, TCPort]) ->
   U = list_to_integer(UDPort),
   T = list_to_integer(TCPort),

    app:start(), %% Want to pass T into the startup.
  receive
    _ -> ok
  end;

...

app.erl

-module(app).
-behaviour(application).

-export([start/0, start/2, stop/0, stop/1]).

-define(PORT, 4300).

start () -> application:start(?MODULE). %% This is called by the escript.
stop () -> application:stop(?MODULE).

start (_StartType, _StartArgs) -> supervisor:start(?PORT).
stop (_State) -> ok.

老实说,我不确定使用应用程序是否可行,但我认为最好问一下。

通常的方法是从 shell 刚刚调用

的任何东西开始
erl -run foo

不过你也可以

erl -appname key value

设置环境值然后

application:get_env(appname, key)

获取您正在寻找的值。

也就是说...

我喜欢让服务应用程序成为无需关闭即可(重新)配置的东西。我通常包含一些消息协议,如 {config, Aspect, Setting} 或类似的消息协议,可以动态改变服务的基本状态。因为我经常这样做,所以我通常只是让启动应用程序的脚本也向它发送配置消息。

考虑到这一点,考虑这个粗略的概念示例:

!/usr/bin/env escript
%% -*- erlang -*-

-export([main/1]).

main([UDPort, TCPort]) ->
    U = list_to_integer(UDPort),
    T = list_to_integer(TCPort),
    ok = case whereis(app) of
        undefined ->  app:start();
        _Pid      ->  ok
    end,
    ok = set_ports(U, T).

%% Just an illustration.
%% Making this a synchronous gen_server/gen_fsm call is way better.
set_ports(U, T) ->
    app ! {config, listen, {tcp, T}},
    app ! {config, listen, {udp, U}},
    ok.

现在启动脚本不仅是启动脚本,还是配置脚本。关键不是要有启动脚本,而是要在您指定的端口上提供服务 运行ning。当然,这并非适用于所有工具的概念,但它应该会给您一些想法。除了其他技术(例如在应用程序规范中包含端口等)之外,还有一种做法是将配置文件放在应用程序知道要查看的地方并仅从中读取术语。

编辑

我刚刚意识到您是在一个脚本中执行此操作的,该脚本会在您每次调用它时生成一个新节点。要使上述技术正常工作,您需要使 escript 名称成为 运行 服务的节点,如果它已经存在,则找到它。