Running Elixir agents from the web, using Phoenix

2014-05-05

This is a walkthrough, not quite step by step, of how to get a webpage working using the new Phoenix web framework and the Elixir programming language. And, we should be able to use one of the powerful features of Erlang, the OTP actor/agent library.

I am not an expert in Elixir, or Erlang for that matter. I’m just trying to lean a little bit more about how these technologies work, and I am recording my observations as I go.

Also, note that I’ll be doing this walkthrough on Ubuntu. Being a Windows developer, I tried to get this working on Windows first. However, there is currently an issue with building Phoenix in a Windows environment. The dev team is currently working on this issue, so hopefully it will be addressed soon.

Getting set up

First, we need to get all of our requirements in place so that we can get started. When downloading, be sure to grab the latest versions of all programs. Install Erlang by downloading the source and building as described in the tutorial. Then install Elixir. I also download and build the source. Then make sure you are able to run the commands erl and mix. I am using version 17.0 of Erlang and 13.1 of Elixir.

Next we will need to clone the Phoenix project. After cloning, cd into phoenix directory and run the following from a command prompt:

1
mix do deps.get, compile

This will download some more dependencies and compile Phoenix. Now, just pop open a text editor and we can get started.

Hello World with Phoenix

Lets see if we can serve a page using Phoenix. From the same directory that we just compiled Phoenix in, run the following, which will create a new project which we should be able to start running right away.

1
mix phoenix.new web_agent ../web_agent

Now, cd into that directory and run the following.

1
2
mix do deps.get, compile
mix phoenix.start

This will compile your new project, and then start a webserver. Open a browser to http://localhost:4000 and you should see “Hello world”.

Now for some changes

Now that we know we have something working, lets try adding some new functionality. Since Phoenix is an MVC framework, we are going to need to make some changes to each part of our app to take advantage of how Elixir and Erlang work.

First things first, get back to your terminal window. You can stop the webserver with Ctrl+C followed by a.

Controlling the results

Now, lets make some changes to the Controller. Right now, it is just returning a text result with a string. Lets make it return an html file instead. Open up lib/controllers/pages.ex, and make it look like the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
defmodule WebAgent.Controllers.Pages do
use Phoenix.Controller
def index(conn) do
html conn, File.read!("index.html")
end
def write_data(conn) do
message = conn.params["message"]
pid = spawn(WebAgent.DoWork, :write, [])
send pid, {:message, message}
text conn, ""
end
end
defmodule WebAgent.DoWork do
def write do
receive do
{:message, m} -> IO.puts "Print message " <> m <> "from process #{inspect self()}"
end
end
end

The index controller action is going to return the index.html page to the user. The write_data action will be set up as a post action, which we can use to spin up a new process. This is done with the spawn command.

The other module defineswrite, which is a function we will be launching in a different process. This prints out the message we send, and the process id.

View for the browser

Now, we need to make a page to serve up. Create a new file in our main web_agent folder called index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<html>
<head>
<title>Web Agents</title>
<script src='static/js/jquery.min.js' type='text/javascript'></script>
<script type='text/javascript'>
function sendMessage(){
$.post('/' + $('#message').val());
};
</script>
</head>
<body>
<div>
<h1>Write a mesage</h1>
</div>
<div>
<input type='text' id='message'></input>
<button type='submit' onclick='sendMessage();'>Send</button>
</div>
</body>

This is just a basic page with a little javascript to post our data to the server.

Routing to the controller

And, now we need to make a few changes to our routes file so that we can access the new controller action we created. The routes file is located in /lib/web_agent/router.ex. Make it so:

1
2
3
4
5
6
7
8
defmodule WebAgent.Router do
use Phoenix.Router
plug Plug.Static, at: "/static", from: :web_agent
get "/", WebAgent.Controllers.Pages, :index, as: :page
post "/:message", WebAgent.Controllers.Pages, :write_data
end

The new route is going to handle the post to ‘/‘ and call the write_data method.

A few more things

To finish up, download jquery.min.js and save it to the /priv/static/js/ folder. The “/static” handler will get this for us when we need it, without us having to write any controller code.

Now, recompile the project and restart the webserver. You can do both using the following command:

1
mix do compile, phoenix.start

Refresh the page and see what happens. You should be able to send a message to the server by entering some text and hitting send. This calls the post write_data method, which kicks off a new process. This process will then print a message out to the console. Notice that hitting send more than once will result in a different process id each time.

Is that it?

This is really just a starting point. I was interested in working with Elixir, and toying around with a web framework. There aren’t many examples or samples of using Phoenix yet, so I wanted to share my experiences. I also wanted to share an example of using the Erlang process system being used from a web framework.

If you are looking for something more in depth and just want to read some code, take a look at the mogo chat project which uses Pheonix.