cc by-sa flurdy

Play! 2.0 + Scala + Heroku

Play!
Heroku

Develop even quicker & deploy easily to the Cloud

(Ubuntu + Git + IntelliJ + Apache)


Contents

  1. Aim
  2. Why & what
  3. Pre-requisites
  4. Install Scala
  5. Install Play
  6. Install IntelliJ
  7. Install Heroku
  8. Create project
  9. Develop application
  10. Deploy to Heroku
  11. Add ons
  12. Load balancing with Apache httpd
  13. Staging/environments
  14. Even faster Play!
  15. Database
  16. Extensions
  17. References
  18. Help
  19. Feedback
  20. Revision
wont fix t-shirt
shirts.flurdy.com

For Play! 1.x & Java, please read my Play! 1.x guide.

Aim

Why

What is Play!

The Play! framework is a web application framework that can be used with Java or Scala. And it makes it easy, quick but also powerful. By purposfully not adhering to the outdated j2ee spec, Play!'s api is much cleaner and RESTful. Its feature of dynamic class reloading makes development very quick.

Play! 1.x

Play! 1.2.x is an excellent version of the framework. It is stable, have a huge range of plugins and a lot of documentation. For a production system it is the one I would suggest.

Java is a first class citizen with Play! 1.x and is the language to use. Scala is supported from version 1.2.x, however the Java support is more polished.

My original Play! + Heroku guide uses Play! 1.2.x.

Play! 2.0

At the time of writing Play! 2.0 is not yet released, and is still in Release Candidate stage. As such I would not recommend it for production. Yet. I would even wait for teething bugs and plugin maturity to settle down until version 2.0.2 or 2.1.

Play! 2.0 is not a normal version progression. As it really changes a lot it should have been called version 14.0 or rather rename the whole framework to RePlay or something...

But Play! 2.0 is another leap forward towards a fantastic framework. Scala is now a first class citizen, and while officially Java is still first class it really feels less supported. For that reason I would only recommend Scala with Play 2.0.

With 2.0 they have added Anorm or EBeans instead of JPA, SBT instead of their own builder/Maven, CoffeScript instead of JavaScript, Less instead of CSS, Scala templates instead of Groovy templates, etc.

What is Heroku

Heroku is a cloud based application platform or PAAS (Platform as a Service). Or a "Polyglot Cloud Application Platform" according to James Ward. It runs on top of Amazon AWS ec2, but you do not need to know anything about that. The interface is so easy and quick to use which is why I like it. The big bonus is that if you only run one "web server" (dyno) per application it is free. Only when you need to scale or add special features do you need to pay anything. And then it is mostly pay as you go, so not locked in for the year. Another neat feature of Heroku is the use of Git as deployment tool.

Pre-requisites

Ubuntu

This guide will assume Ubuntu is your OS. However any Linux distro will be fine, Mac OSX will also be quite similar. Windows will be different but with similar steps.

Java

Since Oracle decided to disallow security updates for Java 6 on Ubuntu, I will assume OpenJDK 7.

sudo aptitude install openjdk-7-jdk

You can alternatively install Oracle Java 7 via a PPA.

Git

Heroku's deployment model uses Git so while you don't need to be a git guro, you do need to use it.

sudo aptitude install git gitk

Install Scala

You can use the package managed version

sudo aptitude install scala

But in many cases these versions lag behind so here is how to manually install it:

Download from scala-lang.org

wget http://www.scala-lang.org/downloads/distrib/files/scala-2.9.1.final.tgz

Untar it and move to the library:

tar xzf scala-2.9.1.final.tgz;
sudo mv scala-2.9.1.final /usr/local/lib/;
cd /usr/local/lib/;
sudo ln -s scala-2.9.1.final scala

Add scala to the PATH in /etc/environment: sudo vi /etc/environment PATH="$PATH:/usr/local/lib/scala/bin"

Restart (or manually add to $PATH) and test via

scala --version

Install SBT

Following SBT install steps by:

Download the SBT jar

wget http://typesafe.artifactoryonline.com/typesafe/\
  ivy-releases/org.scala-tools.sbt/sbt-launch/0.11.2/sbt-launch.jar;
sudo mkdir /usr/local/lib/sbt;
sudo mv sbt-launch.jar /usr/local/lib/sbt/

Create an executable script:

sudo touch /usr/local/bin/sbt;
sudo chmod +x /usr/local/bin/sbt;
sudo vi /usr/local/bin/sbt
java -Xms512M -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled
  -XX:MaxPermSize=384M -jar `/usr/local/lib/sbt/sbt-launch.jar "$@"

      (Enter this command all on one line)


Alternatively you could install the whole Typesafe stack

Install Play!

An ubuntu deb package would be nice officially or via a PPA. But I have not found a useable one.

Download the latest 2.x version from download.playframework.org/releases (currently 2.0-RC3)

wget http://download.playframework.org/releases/play-2.0-RC3.zip

Unzip and move to a library position

unzip play-2.0-RC3.zip;
sudo mv play-2.0-RC3 /usr/local/lib/;
cd /usr/local/lib;
sudo ln -s play-2.0-RC3 play2;

Add play to your path by editing /etc/environment

sudo vi /etc/environment

Append play path to the PATH property

PATH="/usr/local/..../usr/games:/usr/local/lib/play"

To delay relogging in to activate the /etc/environment changes

export PATH="$PATH:/usr/local/lib/play2"

To test if it works

play help

Together with Play! 1.x

If you also want to use Play! 1.x at the same time:

Do not add /usr/local/lib/play2 to the PATH in /etc/environment

Instead create an alias in ~/.bash_aliases

vi ~/.bash_aliases alias play2="/usr/local/lib/play2/play"

To test if it works

play2 help

For the rest of the document remember to use play2 instead of play.

Install IntelliJ

If you can afford the Ultimate edition (or get work to pay for it) then great as it has from version 11 built in support for Play. However I can not afford it so I will describe the Community edition.

Download IntelliJ from www.jetbrains.com/idea/download/

Unpack it and move to an appliation location

tar xzf ideaIC-11.tar.gz;
sudo mkdir -p /opt/jetbrains;
sudo mv idea-IC-111.69 /opt/jetbrains/;
cd /opt/jetbrains;
sudo ln -s idea-IC-111.69 idea

You can now start IntelliJ with:

/opt/jetbrains/idea/bin/idea.sh

Or add /opt/jetbrains/idea/bin folder to your PATH variable like we did with Play, or create a Unity launcher.

Install Heroku

Basically we are following step 1-3 of the Heroku quickstart article

Register

First sign up to Heroku.

Install toolbelt

To use Heroku's command line tool called Toolbelt you need to add a PPA repository (toolbelt.herokuapp.com/ubuntu) and install heroku-toolbelt. Either do it via Ubuntu Software Center, Synaptic or by the commands below:

sudo apt-add-repository 'deb http://toolbelt.herokuapp.com/ubuntu ./';
curl http://toolbelt.herokuapp.com/apt/release.key | sudo apt-key add -;
sudo aptitude update;
sudo aptitude install heroku heroku-toolbelt;

Log into Heroku

On initial login it will ask you to upload a SSH public key. If you have one already you can reuse it, or you can manually create one before hand, or Heroku will create one for you.

heroku auth:login

Create project

As detailed in Plays wiki

play new pizzeria

Accept pizzeria as the project name, and select a simple Scala project.

Then set up version control.

cd pizzeria;
git init;
git add .;
git commit -m "Initial"

Create an IntelliJ module.

play idea

(You probably want to add *.iml, *.ipr and .idea to the .gitignore file)

Now open IntelliJ IDEA. And create a new project.

Import the pizzeria module as an existing module.

Develop application

As Play continously reloads classes while in development mode, we start the Play application first.

play run

If you go to localhost:9000 you will see the initial page for your application.

Front & about pages

Next we will then set up a controller and some views

In your IDEA open app/controllers/Application.scala. Notice the index method:

...
  def index = Action {
     Ok(views.html.index("Your new application is ready."))
  }
...

This controller method returns the HTTP response code OK with a string as paramter. It will render the view app/views/index.scala.html. If you open this file:

@(message: String)

@main("Welcome to Play 2.0") {

  @play20.welcome(message)

}

Play! 2.0 uses Scala as templating language. Main feature is that every use of the '@' character' indicate a template command. To actually displat a '@' escape it by entering a double '@': '@@'.

First line tells you this template requires a parameter of type String. 3rd line tells you it is a subset of another layout template main.scala.html, of which it passes a parameter to (its title). The @play20.welcome(message) shows a custom macro tag which is all the welcome blahbla you see on the front page.

Modify the app/views/index.scala.html file to:

@()

@main("Pizzeria") {

<h1>Pizzeria</h1>
<ul>
  <li><a href="@routes.Application.about())">About</a></li>
</ul>

}

Notice the @routes link to a method in Application controller.

Since we no longer need a parameter for this template, modify the index in app/controllers/Application.scala.

...
  def index = Action {
     Ok(views.html.index())
  }
...

If you refresh your browser window (localhost:9000), you will now get an error. This is because the URL link in the list above is not yet implemented.


About

Lets add another page. Open app/controllers/Application.scala. And add this method:

...
  def about = Action {
     Ok(views.html.about());
  }
...

Again a very simple method, and you need to create the view at app/views/about.scala.html.

@main("About the Pizzeria") {

<h1>About the Pizzeria</h1>
<p>
  Lorem ipsum dolor sit amet, arcu et leo lacinia etiam
  viverra fames, facilisi inceptos ultricies vitae tristique
  phasellus, leo ut proin cum dictumst ultricies ultricies
</p>

}

If you reload the front page, you will still get an error. That is because in Play 2.0 every link needs to be resolvable via the routes file (below).

Routes

We like tidy RESTlike urls so you need to edit the conf/routes file. Modify it by adding the about line, similar to:

...
# Home page
GET    /                      controllers.Application.index
GET    /about.html            controllers.Application.about
...

You can read more about controllers, template views and routes in the Play! 2.0 documentation.



Pizza order form

More interesting than the above mostly static templates are forms and binding to objects within Play. We will create a pizza order form, and relevant controllers for dealing with the order. (You may apply TDD for this development using Play's built in testing support).

Create a new controller at app/controllers/PizzaOrder.scala.

package controllers;
import play.api._
import play.api.mvc._
import play.Logger;

object PizzaOrder extends Controller {

  val pizzaForm: Form[] = Form(
    tuple(
      "pizzaType" -> nonEmptyText(maxLength = 128),
      "size" -> nonEmptyText(maxLength = 128),
      "address" -> nonEmptyText(maxLength = 128)
     )
  )

  def showOrderForm = Action {
    Ok(views.html.pizza.orderform())
  }
}

The pizzaForm is the form used and the showOrderForm method is a simple template redirection to show the form.

Create the template app/views/pizza/orderform.html

@(pizzaForm: Form[(String,String,String)])

@import helper._

@main("Pizza order") {

<h1>Pizza order</h1>
@form(routes.PizzaOrder.orderPizza()) {
  <fieldset>
    <legend>Choose pizza</legend>
    <select name="pizzaType">
      <option value="margherita">Margherita</option>
      <option value="hawaiian">Hawaiian</option>
      <option value="pepperoni">Pepperoni</option>
      <option value="quattroformaggi">Quattro formaggi</option>
    </select>
  </fieldset>
  <fieldset>
    <legend>Size</legend>
    <input type="radio" name="size" id="sizeMedium"
        value="Medium" checked="checked" />
    <label for="sizeMedium">Medium</label>
    <br/>
    <input type="radio" name="size" id="sizeLarge"
         value="Large" />
    <label for="sizeLarge">Large</label>
  </fieldset>
  <fieldset>
    <legend>Delivery address</legend>
    <input type="text" name="address" />
  </fieldset>
  <button type="submit">Order pizza<button>
}

(We are using Play 2.0's form helpers to simplefy the form generation).

Further modify app/controllers/PizzaOrder.scala by adding methods to receive the order and display a confirmation:

...
def orderPizza = Action { implicit request =>
  pizzaForm.bindFromRequest.fold(
    errors => BadRequest(html.pizza.orderPizza(errors)),
    pizzaOrder => {
      Logger.info("Ordering pizza: " pizzaOrder.pizzaType);
      // business order logic
       Redirect(routes.PizzaOrder.pizzaOrdered())
    }
  )
}

def pizzaOrdered(pizzaType: String) = Action {
    Ok(views.html.pizza.ordered(pizzaType))
}
...

The orderPizza method is the real business logic method. It receives form data, binds it to java objects and processes this. (Actually we mostly ignore the data, but a real application would obviously not). Then it calls the pizzaOrdered method for showing a confirmation template. Play will detect this and issue a HTTP redirect to this method, so that you are protected against multiple accidental orders.

Create the template app/views/pizza/ordered.scala.html

@(pizzaType: String)

@main("Pizza ordered") {
  <h1>Pizza ordered</h1>
  <p>
    The @pizzaType pizza will arrive within 40 minuttes!
  </p>
}

We need to tidy up the URLs. We need one (and perhaps two aliases) to show the form, a POST handler for receiving the form, and a confirmation page. Open conf/routes:

...
GET /order/              controllers.PizzaOrder.showOrderForm
GET /order/index.html    controllers.PizzaOrder.showOrderForm
GET /order/new.html      controllers.PizzaOrder.showOrderForm
POST /order/             controllers.PizzaOrder.orderPizza
GET /pizzaOrdered.html   controllers.PizzaOrder.pizzaOrdered(pizzaType: String)
...

Ps. A cleaner way when the form expands is to create a complex object POJO binding instead of individual method parameters.

Ps2. We could also have applied validation constraints.

Send email

A more usefull order flow is perhaps if we are notified of the order!

Play 1.x provides an easy way of sending email. Which I describe in my Play! 1.x guide.

Unfortunatley there is not a built in email module in Play! 2.0. However I have written a blog post about how to send email with Play! 2.0 + SendGrid

Error pages

You can customise the error pages returned by Play! .

You will need to create/modify the Global object: app/controllers/Global.scala

import play.api._
import play.api.mvc._
import play.api.mvc.Results.__

object Global extends GlobalSettings {

  /**
   ** 404: When action methods are not found or unable to bind posts
   **/
  override def onHandlerNotFound(request: RequestHeader) = {
    if (request.path != "/favicon.ico" && Logger.isInfoEnabled)
      Logger.info("Not found: " + request.path)
    NotFound(views.html.notFoundPage(request.path))
  }

  /**
   ** When e.g. the parameters mismatch what routes are defined
   **/
  override def onBadRequest(request: RequestHeader, error: String) = {
    BadRequest("Bad Request: " + error)
  }

  /**
   ** 500: When your code is bad...
   **/
  override def onError(request: RequestHeader, ex: Throwable) = {
    Logger.error("Server error: " + request.path,ex)
    InternalServerError(views.html.errorPage(ex))
  }
}

You will need to create a template for 404s app/views/notFoundPage.scala.html

@(requestPath: String)

@main("404: Not found") {
  <h2>404: Not Found</h2>
  <p>Unfortunately, we could not find [@requestPath]</p>
}

And a 500 app/views/errorPage.scala.html template

@(exception: Exception)

@main("500: Server error") {
  <h2>500: Server error</h2>
  <p>Unfortunately, we really messed up</p>
  <p>Please try again later</p>
  <!-- Exception: @exception.getMessage() -->
}

For further fine grained errors (410, 403, 302, etc) you will need an Apache server in front.

Deploy to Heroku

Configure Heroku

To create a dyno for this application:

heroku create -s cedar

This will create a server for you to deploy to. It will respond with a domain name that your application will run on. Something like blue-moon-123.herokuapp.com.


Whilst Heroku is great at detecting language, framework etc of your application, you need to create a Procfile

vi Procfile

Here is standard to get Play! 2.0 and scala to work:

web: target/start -Dhttp.port=${PORT}

And here is an alternative if you want to use their free Postgresql database and database evolutions (all on one line):

web: target/start -Dhttp.port=${PORT} -DapplyEvolutions.default=true
  -Ddb.default.driver=org.postgresql.Driver -Ddb.default.url=$DATABASE_URL

More on Play! & Heroku's database integration below


Deploy

Make sure everything is added and commited to git:

git commit -am "kitchen sink commit"

Then to deploy your appliction to the dyno created by Heroku:

git push heroku master

Now either open a browser and type in the dyno's domain name or execute:

heroku open



Voila!



Error on deployment

If for some reason your application does not deploy successfully the first time, you may need poke Heroku to get your application to run, even after you fix the initial problem and deploy successfully.

The problem is that Heroku might not assign any Dynos to your application if it fails to deploy the first time. So you need to poke it by (re)assigning a Dyno:

heroku scale web=1;
heroku ps start

Add ons

Heroku offers a range of add-ons to add to your application. Most are free or at least free initially and only start to charge once you application requires heavy load or further scaling.

Custom domain name

The URL blue-moon-123.herokuapp.com is fine to use while testing and developing. But in many production situation it is not ideal. So you can add the domain name add-on, which will listen to requests of that name if the dns aliases to blue-moon-123.herokuapp.com.

More practically in my situation is that this enables the Play application to know it is listening to your real domain name. And so that you can put an Apache httpd server infront as a load balancer while still proxying to blue-moon-123....

heroku domains:add myapp.example.com

(Note Heroku now includes Custom domain addon by default).

(Note2 in Play's conf/application.conf you can also hard code the production domain name under %prod.application.baseUrl).

Send email

If you need more customisation like not involving Google for example, among several choices is SendGrid add-on.

Logging

Several choices including the plain Logging add-on.

Database

There are multiple databases available as add-ons. From standard RDBMS like PostgreSQL and MySQL (with Amazon RDS as an option as well) to NoSQL DBs like MongoDB, Redis and CouchDB to in memory caching solutions like Memcache.

And many more.

Apache httpd in front of Play applications

You do not need to have an Apache Httpd server in front your Play application(s). Especially if you have added the Custom Domain add-on.

However I do so that I can switch between Heroku and applications hosted elsewhere. And enable smooth load balancing especially during rollout staging. The fact I already run a httpd server means no increased cost for me.

Play also document how to configure lighthttpd as proxy infront of Play, I will however use Apache.

Reverse proxy

As part of my AWS ec2 guides I detail how to relay traffic from between Apache Httpd and Tomcat servers. And in this situation we need to do the same.

I am asuming you already have an Apache server up and running. If not, follow my AWS ec2 Apache Httpd and Tomcat servers guide. In that I detail how to set up the servers. I also describe how to relay traffic from between Apache Httpd and Tomcat servers and in this situation we need to do something similar.

You need to install and enable the Reverse proxy module.

sudo aptitude install libapache2-mod-proxy-html;
sudo a2enmod proxy_html

Ensure you are not exposing your server as a normal proxy, by stating ProxyRequests Off.

sudo vi /etc/apache2/mods-enabled/proxy.conf ...
ProxyRequests Off
...

Open you virtual host and modify to something like these proxy lines

sudo vi /etc/apache2/sites-available/example.com
ServerName www.example.com
...br/> <IfModule mod_proxy.c>
  ProxyPreserveHost On
  ProxyPass /pagenottoproxy.html !
  ProxyPass / http://blue-moon-123.herokuapp.com/
  ProxyPassReverse / http://blue-moon-123.herokuapp.com/
</IfModule mod_proxy.c>
...
</VirtualHost>

Activate changes with

sudo apachectl -t;
sudo service apache2 reload

Load balancing with Apache httpd

The main benefit with having a httpd server in front of Play applications is the ability to load balance smoothly.

Enable the balancer module.

sudo a2enmod proxy_balancer

Modify your virtual host file similar to this:

sudo vi /etc/apache2/sites-available/example.com
ServerName www.example.com
...
<Location /balancer-manager>
  SetHandler balancer-manager
  Order Deny,Allow
  Deny from all
</Location>
<IfModule mod_proxy.c>
  ProxyPreserveHost On
  ProxyPass /pagenottoproxy.html !
  <Proxy balancer://mycluster>
    BalancerMember http://blue-moon-123.herokuapp.com
    BalancerMember http://apps.example.com:9000 status=+H
  </Proxy>
  ProxyPass / balancer://mycluster/
  ProxyPassReverse / http://blue-moon-123.herokuapp.com/
  ProxyPassReverse / http://apps.example.com:9000/
</IfModule mod_proxy.c>
...
</VirtualHost>

In this example we use Heroku but also the application is deployed to a different server on port 9000.

The stats=+H of the second balancer member indicate that this member will only be used when no other can be reached. So this configuration is a fail-over load balancer.

Do remember Heroku will do load balancing for you. But this configuration is nice for staging rollout, and for simple switchover to alternative hosting.

Rollout staging

For a smooth rollout you can use Heroku and load balancing. Note when deploying Play it will initially be unvailable due to when running in Production mode it will pre-compile all classes, so a smooth rollout makes a difference.

  1. Deploy your current version to a 2nd Heroku server, e.g. young-nebula-123.herokuapp.com
  2. Test 2nd server is up and running by goin to young-nebula-123...
  3. Configure your Apache server to load balance as detailed above
    1. Replace apps.example.com:9000 with young-nebula-123.herokuapp.com/
    2. Make the 2nd server the default (not the +H one)
    3. Test all okay
  4. Upgrade the 1st server by pushing new code
  5. Test upgraded version is up and running (by going directly to blue-moon-123.herokuapp.com)
  6. Make the 1st server the default balancer member again
  7. Remove the 2nd server from load balancer
  8. Shutdown the 2nd Heroku server

With Heroku's pricing model you only need to pay for those few minuttes the second server is running.



Staging/environments

Heroku does support having staging so that you can have separate instances on Heroku for your different staging and testing levels.

For thorough examples read the Heroku page on multiple environments.



Even faster Play!

Auto compile

Instead of play run launch SBT with just play

Then within SBT run the command ~run (Note the ~tilda~ before the run command.)
Play! will now continually scan you files and compile them as soon as it detects a change. This saves time as by the time you try to reload a page it will be already be compiled. But especially it will save time as the compiler will complain immediately if there is anything wrong with the updated code.

Auto test

Even more usefull is this command within SBT: ~test This will continually scan for changes compile your code and then run all your unit tests. This allows quick feedback when you unintentially brake something, or might have fixed something...





Database

Local development database

Locally it makes sense to use the supplied in memory H2 database. It is by default enabled in conf/application.conf by these settings:

db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
Heroku's free DB

Heroku offer a free PostgreSQL database instance for every application. Their PostgreSQL offering is well documented. The free offering used to be a shared database instance, but recently they started to offer a development DB instead. There are plenty of production scaleable db offerings. As well other database types and vendors as add-ons.

Configure Play! to use Heroku's database

Create/modify your Procfile

web: target/start -Dhttp.port=${PORT} -DapplyEvolutions.default=true
  -Ddb.default.driver=org.postgresql.Driver -Ddb.default.url=$DATABASE_URL

($PORT and $DATABASE_URL will be populated by environment variables on the Heroku side)

Add PostgreSQL as a dependency. Open Project/Build.scala

val appDependencies = Seq(
   "postgresql" % "postgresql" % "9.1-901-1.jdbc4"
}
Evolutions

Evolutions are a way to update and evolve your database schema and data that Play! suggest. To enable the evolutions to be executed in productions automatically, add this line to conf/application.conf.

applyEvolutions.default=true
Database reset

While in development you often just wants to reset Heroku's shared database as there is no production data to persist.

heroku pg:reset SHARED_DATABASE

You will need to confirm by entering your heroku instance's name as described by heroku's output.

Anorm

Play have created its own database access layer called Anorm. It abides by the rules that ORMs are an overkill and a good developer should now SQL and not be afraid of it.

Play! 2 database examples




Extensions

Next possible steps could be:

References

I wont fix your computer

Help

If you need assistance, please use these channels:

Or hire me (www.eray.co.uk) for:

Feedback

Revision