So far we haven’t needed to give our node a name—we’ve had only one. If we ask Elixir what the current node is called, it’ll give us a made-up name:
| iex> Node.self |
| :nonode@nohost |
We can set the name of a node when we start it. With IEx, use either the --name or --sname option. The former sets a fully qualified name:
| $ iex --name wibble@light-boy.local |
| iex(wibble@light-boy.local)> Node.self |
| :"wibble@light-boy.local" |
The latter sets a short name:
| $ iex --sname wobble |
| iex(wobble@light-boy)> Node.self |
| :"wobble@light-boy" |
The name that’s returned is an atom—it’s in quotes because it contains characters not allowed in a literal atom.
Note that in both cases the IEx prompt contains the node’s name along with my machine’s name (light-boy).
If You Run OS X | |||||||
---|---|---|---|---|---|---|---|
Apple did something strange a while back—the local hostname is resolved only if you have particular sharing services enabled. If they aren’t enabled, then you can’t access your computer using its name. This means that Elixir can’t find it when using the --sname option. The simplest fix, which is a bit of a hack, it to add your machine’s name to your /etc/hosts file. First find the name:
|
Now I want to show you what happens when we have two nodes running. The easiest way to do this is to open two terminal windows and run a node in each. To represent these windows in the book, I’ll show them stacked vertically.
Let’s run a node called node_one in the top window and node_two in the bottom one. We’ll then use the Elixir Node module’s list function to display a list of known nodes, then connect from one to the other.
Window #1 | ||||||||||||||
| ||||||||||||||
Window #2 | ||||||||||||||
|
Initially, node_two doesn’t know about any other nodes. But after we connect to node_one (notice that we pass an atom containing that node’s name), the list shows the other node. And if we go back to node one, it will now know about node two.
| iex(node_one@light-boy)> Node.list |
| [:"node_two@light-boy"] |
Now that we have two nodes, we can try running some code. On node one, let’s create an anonymous function that outputs the current node name.
| iex(node_one@light-boy)> func = fn -> IO.inspect Node.self end |
| #Function<erl_eval.20.82930912> |
We can run this with the spawn function.
| iex(node_one@light-boy)> spawn(func) |
| #PID<0.59.0> |
| node_one@light-boy |
But spawn also lets us specify a node name. The process will be spawned on that node.
| iex(node_one@light-boy)> Node.spawn(:"node_one@light-boy", func) |
| #PID<0.57.0> |
| node_one@light-boy |
| iex(node_one@light-boy)> Node.spawn(:"node_two@light-boy", func) |
| #PID<7393.48.0> |
| node_two@light-boy |
We’re running on node one. When we tell spawn to run on node_one@light-boy, we see two lines of output. The first is the PID spawn returns, and the second is the value of Node.self that the function writes.
The second spawn is where it gets interesting. We pass it the name of node two and the same function we used the first time. Again we get two lines of output. The first is the PID and the second is the node name. Notice the PID’s contents. The first field in a PID is the node number. When running on a local node, it’s zero. But here we’re running on a remote node, so that field has a positive value (7393). Then look at the function’s output. It reports that it is running on node two. I think that’s pretty cool.
You may have been expecting the output from the second spawn to appear in the lower window. After all, the code runs on node two. But it was created on node one, so it inherits its process hierarchy from node one. Part of that hierarchy is something called the group leader, which (among other things) determines where IO.puts sends its output. So in a way, what we’re seeing is doubly impressive. We start on node one, run a process on node two, and when the process outputs something, it appears back on node one.