Lethi
Lethi

Reputation: 1177

Connecting to Nodes from scripts?

I am trying to test a system by calling a function I have written, which is in a script and is compiled on the Erlang shell (on windows).

The function connects to other nodes (which are running).

I am getting a problem stating that "Can not start erlang:apply,[......" and I think this is because I have not started the shell to act as a distributed node.

Could someone please advise what I need to do to be able to run a script from the shell, which messages other Nodes?

Upvotes: 2

Views: 1309

Answers (2)

archaelus
archaelus

Reputation: 7129

To start erlang distribution from an escript, you either need to pass the -name Name argument as a hot comment %%! -name Name in your escript, or you need to start distribution manually. I wrote an example for Erlang Factory 2011 (talk here -- http://www.erlang-factory.com/conference/SFBay2011/speakers/GeoffCant ).

I also have a link to example code to start erlang distribution in an escript from the github repo I used in the talk.

It boils down to:

net_kernel:start([Name, longnames]),
erlang:set_cookie(Name, list_to_atom(Cookie)).

Upvotes: 3

zetavolt
zetavolt

Reputation: 3217

Theres two things potentially wrong,

One, you simply are not set up as a node. On windows, you can fix this by passing "-node NodeName" into werl in a similar fashion to Unix, e.g:

$ erl -name zephmatic
(zephmatic@kerneltrap)1> node().
'zephmatic@kerneltrap'

If you've already set up the node name (just to be sure run node(). and erlang:get_cookie() in Erl!), I'm guessing it's the the actual node messaging semantics in erlang you're having trouble with -- This is an understandably broad topic and the entire Erlang language is almost wholly focused on solving the puzzle of correct messaging primitives. The canonical OTP reference is Distributed Erlang, but a humorous and (in my opinion) excellent introduction to the topic is Learn You Some Erlang For Great Good.

If it's helpful to your immediate needs, here's some sample code for manipulating gen_server behavior that I've tested, feel free to invoke it, connect to it, and get high quality distributed programming for less (For a unlimited time only)!

Best of luck, and don't take over the world too quickly when you have the power of a billion machines at your disposal!

-module(communicate).
-author('Zephyr Pellerin').

-behavior(gen_server).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-export([start/0, grab/2, lookup/1, return/1]).

%%% The reason I declare all of these is to make calling
%%% namespaced functions easier, i.e, simply calling start(). 
%%% rather than gen_server:start_link()
start() ->
  gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
grab(Which, Element) ->
  gen_server:call(?MODULE, {grab, Which, Element}). 
lookup(Element) ->
  gen_server:call(?MODULE, {lookup, Element}).
return(Element) -> 
  gen_server:call(?MODULE, {return, Element}).

% The init method is a "callback" (Whatever that designation may imply)
% that occurs when another client connects
init([]) ->
    Resource = dict:new(),
    {ok, Resource}.

%%% The Generic server specifies that handling calls happens
%%% through handle_call, which would have thought!
%%% If you're not very experienced with Erlang, this below might seem
%%% strange to you -- it's just different ways to handle 
%%% input given differing "types" (Not a real thing in Erl). 

% This function simply looks to see if an element from
% a "Resource" is in use, if not it tells the other node
% that it is locked, or returns it if not.
handle_call({grab, Which, Element}, _From, Resource) ->
    Response = case dict:is_key(Element, Resource) of
        true ->
            NewResource = Resource,
            {locked, Element};
        false ->
            NewResource = dict:append(Element, Which, Resource),
            ok
    end,
    {reply, Response, NewResource};

% This function checks for the existence of an element 
handle_call({lookup, Element}, _From, Resource) ->
    Response = case dict:is_key(Element, Resource) of
        true ->
            {which, lists:nth(1, dict:fetch(Element, Resource))};
        false ->
            {not_locked, Element}
    end,
    {reply, Response, Resource};

% This uses scary language to annihilate an element! 
handle_call({annihilate, Element}, _From, Resource) ->
    NewResource = dict:erase(Element, Resource),
    {reply, ok, NewResource};

% These are simply functions that must be defined according to gen_server
% its not so special.
handle_call(_Message, _From, Resource) ->
    {reply, error, Resource}.
handle_cast(_Message, Resource) -> 
    {noreply, Resource}.
handle_info(_Message, Resource) ->
    {noreply, Resource}.

% You need to have a method that knows when to fold em' if someone requests termination

terminate(_Reason, _Resource) ->
    ok.

% While not *strictly* nessasary, this is a cool method that allows you to inject code
code_change(_OldVersion, Resource, _Extra) -> 
    {ok, Resource}.

Upvotes: 1

Related Questions