Running Erlang Webmachine on Heroku
When Heroku released their new stack Cedar they opened the door for a whole new set of components to run on their platform. To support running other components on Heroku you need a build pack that tells Heroku how to build and run your app. Heroku’s published a build pack for Erlang as well as a demo app. This demo app uses straight up Mochiweb as a web server.
MochiWeb is an Erlang library for building lightweight HTTP servers.
Webmachine runs on top of Mochiweb and is
A REST-based system for building web applications.
In this blog post I’ll show how to get a Webmachine app running on Heroku.
Let’s get to it
So here are the steps to get a vanilla Webmachine app up and running on Heroku.
$ git clone git://github.com/basho/webmachine $ cd webmachine $ make $ ./scripts/new_webmachine.sh my-erlang-app /tmp $ cd /tmp/my-erlang-app $ make
You can now run “./start.sh” and open your browser on http://localhost:8000 and see your new awesome Hello World Webmachine app. Now we want to deploy it to Heroku.
Make sure you have Ruby and the Heroku gem installed. If not run:
$ gem install heroku
Then setup our app:
$ git init $ heroku create my-erlang-app -s cedar $ heroku config:add BUILDPACK_URL=http://github.com/heroku/heroku-buildpack-erlang.git
This initializes a new Git repository in our app directory, creates the heroku app. The final line setups the build pack that cedar should use when deploying the app.
Let’s add the source files to the Git repo and start hammering out some code.
$ git add Makefile README rebar rebar.config start.sh src/* priv/dispatch.conf
Next we want to update our rebar.config:
%%-*- mode: erlang -*-
{sub_dirs, ["rel"]}.
{deps_dir, ["deps"]}.
{erl_opts, [debug_info]}.
{deps, [{webmachine, "1.9.*", {git, "git://github.com/basho/webmachine", "HEAD"}}]}.
Create the Procfile which Foreman will use to control our app:
web: erl -pa ebin deps/*/ebin -noshell -boot start_sasl -s reloader -s my-erlang-app
You know have the major components in place for Heroku deployment. If you want to test it out run:
$ ./rebar get-deps compile $ foreman start
Of course this requires that you’ve Foreman in your path. If not install Ruby and run “gem install foreman”. If all goes well your app will start up and you’ll be able to point your browser to http://localhost:8000 and see the output.
Before we can push to Heroku we need to update the application start up code for the generated Webmachine app. When Cedar attempts to start your application it’ll define the port on which your app should listen/bind. Hence we need to read out this value and tell Webmachine to use it. Also we want to update the logging, basically turning it off (more about this later) and we want to just bind to the default catch all ip of 0.0.0.0.
Open up my_erlang_app_sup.erl in the src/ directory.
Change the init method so it looks like this:
init([]) ->
{ok, Dispatch} = file:consult(filename:join(
[filename:dirname(code:which(?MODULE)),
"..", "priv", "dispatch.conf"])),
Port = list_to_integer(os:getenv("PORT")),
io:format("start web server on port ~p~n", [Port]),
WebConfig = [
{ip, "0.0.0.0"},
{port, Port},
% {log_dir, "priv/log"},
{dispatch, Dispatch}],
Web = {webmachine_mochiweb,
{webmachine_mochiweb, start, [WebConfig]},
permanent, 5000, worker, dynamic},
Processes = [Web],
{ok, { {one_for_one, 10, 10}, Processes} }.
This reads out the port number that Cedar has assigned to our app in line 6 and passes it to the Webmachine config. Also it binds to the right IP in line 9 and disables the log dir in line 11.
Make sure it compiles by running the rebar command again:
$ ./rebar get-deps compile
Before we push to Heroku you might want to change the output message of your app. Open “src/my_erlang_app_ressource.erl” and change the “to_html” function.
Now do the add and commit dance to git:
git add <input-changed-file-list-here> git commit -m "initial commit before push to Heroku"
Next run
$ git push heroku master
Point your browser to http://my-erlang-app.heroku.com and you should see your output message as defined in “src/my_erlang_app_ressource.erl”.
To see what’s going on when Cedar boots up your app run “heroku logs”. This will spit out the same output you see when you run foreman locally. This is a great (and the) way to debug why your app isn’t starting up.
I’ve pushed my repository to Gibhub and deployed the app to Heroku. It’s called Erloku and you can check it out here
Next steps
Here are a couple of things that I’d like to continue to work on.
- By default Webmachine comes with a logger that outputs to tiles. Since this doesn’t go well with Heroku which expects and redirects output from Standard Output and Standard Error to its logs. Therefore it would be nice to implement a logger for Webmachine that outputs to StdOut and StdErr. Doing this shouldn’t be too hard.
- Get two dynos running an Erlang Node to talk with each other. Cedar probably has walls in place that won’t allow this, but if possible it would be mighty cool.
If you like my writing you should subscribe to my RSS feed.
Giving EM-Smsified Some Server Love
I just pushed the next release of my EM-SMSified gem to Github and Rubygems. This release (0.3.0) adds an EventMachine HTTP server to make it easy to react to SMSified callbacks.
Installing is easy as always:
gem install em-smsified
Using it is equally easy. Here’s an example of a “pong” server that sends a pong back to any received text message:
require 'rubygems'
require 'yaml'
require 'em-smsified'
require 'eventmachine'
require 'evma_httpserver'
smsified = EventMachine::Smsified::OneAPI.new('username', 'password')
EM.run do
Signal.trap("INT") { EM.stop }
Signal.trap("TRAP") { EM.stop }
puts "Hit CTRL-C to stop"
puts "=================="
puts "Server started at " + Time.now.to_s
puts "Starting incoming SMSified callback server"
EM.start_server '0.0.0.0', 8080, EventMachine::Smsified::Server do |s|
s.on_incoming_message do |msg|
puts "Message received " + Time.now.to_s
puts "#{msg.sender_address} says '#{msg.message}' to #{msg.destination_address}"
smsified.send_sms( :message => 'Pong',
:address => msg.sender_address,
:sender_address => msg.destination_address) do |result|
puts "Pong sent " + Time.now.to_s
end
end
end
end
A more elaborate example is up on Github (examples/pong_server.rb).
The server supports incoming messages on which you need to set a subscription (SMSified – Receiving Messages) and delivery notifications. The latter is set up when you send an sms message by adding the :notify_url parameter.
Use cases
Having a server that’s easy to use from EventMachine makes it easy to implement more advanced text message scenarios:
- You could couple this with the em-websocket gem and add easy websocket callbacks from received text messages.
Source on Github as usual, and gem on Rubygems.
If you like my writing you should subscribe to my RSS feed.
Putting EventMachine In the SMSified Gem
I wanted to utilize EventMachine for something and real and since I’ve been tinkering with telephony stuff recently I thought something that sends text messages might be a good candidate. Instead of rewriting everything from scratch I started with the SMSified Ruby gem instead. SMSified is a service by Tropo that makes it really easy to send text messages. Since the service is still in beta sending text messages is free. Pretty neat. SMSified has a Ruby gem that comes with a test suite. Hence I thought it would be a good starting point.
Installing the new gem is easy
gem install em-smsified
Here’s some example code showing how to send an SMS via SMSified:
require 'rubygems'
require 'eventmachine'
require 'em-smsified'
oneapi = EventMachine::Smsified::OneAPI.new(:username => 'user', :password => 'password')
EM.run do
oneapi.send_sms(:address => '14155551212', :message => 'Hi there!', :sender_address => '13035551212') do |result|
puts result.inspect
end
end
The original gem uses HTTParty to do HTTP requests. To mock these in the spec suite the gem used FakeWeb. FakeWeb doesn’t work with EventMachine and therefore my first step was to replace FakeWeb with WebMock, which works with a number of Ruby HTTP frameworks. After that I DRY’ed up the code a bit to contain where HTTP requests were being made. Then I added EventMachine via the EM-HTTP-Request gem. To EM’ify the new library I had to modify the original interface to take an anonymous block. This block gets called when the request to SMSified returns. This is where you can check what was returned and perform any updates. This is shown in the code sample above.
There are more examples in the source tree and there’s also some YARD documentation.
Jason Goecke and John Dyer wrote the original SMSified gem making my job so much easier.
em-smsified on RubyGems.
Source on Github.
If you like my writing you should subscribe to my RSS feed.
TweetHose Released as a Gem
I’ve just released a gem called TweetHose to RubyGems. Here’s the short description of what it is:
TweetHose lets you easily generate a daemon that listens to the Twitter firehose. When keywords you’re interested in appears, you can set up a callback. Should make it easy to create that Justin Bieber tracking app you’ve always wanted.
Install it via a quick:
gem install tweethose
Source is up on Github.
If you like my writing you should subscribe to my RSS feed.
I am a self employed independent software development consultant at