Using giter8 to build Scala REST projects with Unfiltered, Netty and Gatling load testing

At Mind Candy we have a number of different Scala REST services to provide common aspects to our games, for example authentication and moderation.

A standard we have developed is to use an Unfiltered Netty standalone server wrapped with the apache-commons daemon library. Also, we want our services to be well tested, easily deployable, and stable under heavy load. For ease of deployment we use Fabric scripts, and for load testing we use Gatling to hammer the services under different stress-tests to check they are up to standard.

We have quite a few services that have a similar setup, and it was getting tedious to create and configure a new project. So, we created a giter8 script to do it all for us!

Giter8

Giter8 is an awesome command line tool which can create a template project structure for you with example files and sbt configuration.

There are quite a few templates contributed by the community already but none did exactly what we want, so we created our own which we’d like to share.

The template will create an example sbt project that:

  • Uses unfiltered and netty to give you a very simple starting endpoint service which will output ‘Hello, <project>’ when hit
  • Gives you some basic test stubs using Specs2
  • Is setup with gatling load testing with an example scenario
  • Is configured with the sbt-idea plugin (IntelliJ IDEA is our preferred IDE)
  • Is configured with the sbt-assemblysbt-release, and sbt-dependency-graph plugins
  • Has a simple fabric deploy file, unix start/stop scripts, and an example init script

The generated project is structured with 3 sub projects:

  • project-example
    • example-core // Business logic
    • example-resources // Containing the Unfiltered Netty request plan
    • example-server // To control the server hosting the plan

Usage:

First make sure you have setup giter8 using the instructions here. Then fire open a terminal and run:

g8 mindcandy/unfiltered-rest-gatling

There are some options to enter, but most can be left as default (See here for more info). The important ones are:

name => The main projects name
project => The name prepended to each of the sub projects
organization => Used as the basis for packages

Once you’ve entered the properties, giter8 will do its magic and whip you up a full sbt project. After it completes, you can cd to the directory, and run sbt.

Test it:

sbt test

Run it:

sbt run

Now open up your favourite browser and go to http://localhost:8889/<project> where <project> is whatever you specified above, and you should get a “hello, project” message back.

Load test it:

Start the server running in one terminal. In another terminal do:

cd yourproject
sbt
project <project>-server
test-load:run

You should get presented with a choice of different classes to run:

  • Engine → Executes the gatling Engine in interactive mode prompting you which scenario to run
  • BatchEngine → Runs all simulations available in a batch with no user prompts
  • Recorder → Starts the pretty cool Gatling recorder which you can use to create scenarios. Basically, you setup your web browser to use the recorder’s proxy, and then just browse as normal on your webpage. Gatling records all of your actions as a scenario that can be replayed and customised.
Hit the option for BatchEngine, then load the results in your browser to see something like:

Results from Gatling are put in the gatling/results directory. In the example scenario in the giter8 skeleton we simulate 10 users hitting the simple endpoint, ramping up over a 3s duration. The results are rendered in a nice html page with graphs showing exactly what happened during the simulation. The full gatling feature set is quite extensive and worth checking out.

Create IntelliJ IDEA project files:

sbt gen-idea

Run from start script:

First setup jsvc. Then :

sbt assembly
cd bin
chmod +x start.sh
./start.sh

This has the same affect as ‘sbt run’, but using the apache-commons daemon wrapper. Try opening the service in your browser again and it should work as before. Don’t forget to stop the server when you’re done with the ../stop.sh script :)

Other pieces:

There is also a sample init script that is configured for the skeleton in the bin folder, which is a good starting point for creating a complete init script.

Last to mention is there is a small fabric file that provides a (very) basic setup for copying over the built assembly onto a test/integration server. You’d need to configure your host and change the paths as appropriate to use it, but it’s useful as a starting point.

Let us know if you find this useful, and thanks to n8han for providing a great tool!

Migrating a Play 1.2 website to Play 2.0

At Mind Candy there are a number of internal websites used for reporting and communication. For example – reading automated build/test status via some REST APIs and turning this into a nice visual status display for large ‘build screens’. These have been authored in Scala using the Play Framework 1.2.x.

Recently, version 2.0 of the Play Framework came out of beta and so I wanted to convert the existing Play 1.2 websites over to it. Amongst other reasons, the ability to build to a .jar file makes for simpler deployment, which I was keen to have.

I couldn’t find a good guide for migrating from 1.x -> 2.0 so I am sharing my experiences of porting a Scala Play 1.2.x application. I expected that it wouldn’t be too hard as I was already using Scala Templates and controllers. That was mostly true, with a couple of issues.

I did find a handy conversion guide on the Play 2 wiki which can help converting some uses (it has some unfortunate formatting though so I’d recommend copying and pasting it)

Starting the project

I’d previously installed Play via brew so an upgrade was as simple as
brew update
brew upgrade play

This installed Play 2 whilst leaving Play 1.2.4 also installed for easy roll-back for developing older stuff if I need it.

For simplicity and because there were various code changes that I knew I needed to make, I created a new site in a new location using play new. However I then used svn copy to copy over source assets and code before modifying. This means in the future I can pull updates down using “svn merge” as work continued on the old site whilst I was porting it over!

All of the public files which aren’t built – javascript, css, images – were simply copied across. In the future I’ll check Play’s support for LESS CSS and the Google Closure JS compiler but for now I just want to get things working.

Initially I copied across all the controllers, models and views and configuration files, though I expected to have to fix those up as the syntax had changed.

After a quick run of play compile I had a whole host of build errors, unsurprisingly. So to cut these down I commented out a lot of the logic – all the routes except the home page /, all the templates and all the controllers except for those needed by the home page.

I fixed up controller in turn and gradually re-enabled the routes, until I hit an issue with Database models that stopped me from migrating the rest of my application (see below)

Migrating dependencies

There were a number of java libraries used by the web app, for example to talk to a Subversion server. (This is one of the reasons I really like Scala – it’s easy to pull in useful Java libraries) In Play 1 that was defined in dependencies.yml, e.g.:

require:
- org.tmatesoft.svnkit -> svnkit 1.3.7
- org.tmatesoft.svnkit -> svnkit-javahl16 1.3.7

repositories:
- tmatesoft:
  type: iBiblio
  root: "http://maven.studio:8081/nexus/content/repositories/tmatesoft"
  contains:
  - org.tmatesoft.svnkit -> *</code>

Play 2 now uses sbt as its build system and thus uses the standard sbt syntax for dependencies, so I edited the the project/Build.scala file to add dependencies:

object ApplicationBuild extends Build {
  // some definitions omitted

  val appDependencies = Seq(
    "org.tmatesoft.svnkit" % "svnkit" % "1.7.4",
    "org.tmatesoft.svnkit" % "svnkit-javahl16" % "1.7.4",
  )

  val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
    resolvers += "TmateSoft Repository" at "http://maven.tmatesoft.com/content/repositories/releases/",
  )
}

Once the sbt syntax is understood it’s a reasonably simple process to convert dependencies across.

The original play run / test / start / stop command still work, which is helpful. It’s also quite useful to simply run play to get an sbt console and then run ~test which runs test and then re-runs them anytime a source file changes, which is very useful.

For IDE integration, I use IntelliJ IDEA and happily there is an idea command in Play’s SBT which generates an IntelliJ module which has any library dependencies included. However, your code has to build correctly before this works and you probably need to remember to re-run this every time you modify a dependency. If you don’t the IDE won’t show types correctly – typically you will get more ‘false negatives’ of errors showing up in the IDE which will not happen within Play itself.

Migrating the routes file

For some reason the old Routes file had an explicit 404 for the for the favicon. There didn’t seem to be an obvious pure route-based replacement for this and I didn’t need that behaviour so removed the route.

I had to add controllers. to all routes as the full package reference seems to be required now.
e.g. home page changed from
GET / Application.index
to
GET / controllers.Application.index

The syntax for ‘public’ files has changed so I replaced
GET /public/ staticDir:public
with
GET /public/*file controllers.Assets.at(path="/public", file)

I was also serving a single file elsewhere – multiple Assets.at() in the routes file didn’t go well, but I was able to call to add a new method to the Application e.g. ‘serveMyFile’ and then set the routing to be controller.Application.serveMyFile in routes and then have that call the Assets.at() method
e.g.
GET /myfile controllers.Application.serveMyFile
in the Application controller:
def serveMyFile = controllers.Assets.at(path="/path/to/it", file="myfilename.json")

The syntax for parameters in routes has changed and I found that I needed to move the default parameter definitions from the Controller out to the Routes file, using the ?= syntax instead of the Option[T] syntax I had before. That wasn’t hard to do but was slightly irritating in some ways – I’m still not sure if I like having so it in the routes file.

Minor changes to the syntax for parsing out ids from the URL, for example:
GET /versionone/stories/{projectId} versionone.Printer.storiesById
changed to
GET /versionone/stories/:projectId controllers.versionone.Printer.storiesById(projectId: String, timeboxId: String ?= "", template: String ?= "")

Note the additional default parameters being passed. Also in this instance the Id is actually a string, not an Int.

Migrating Controllers

A lot of the package names have changed e.g. play -> play.api so some of the imports needed to be fixed up with the new ‘api’

replaced
import play._
import play.mvc._

with
import play.api._
import play.api.mvc._

With the paths to generated views also changed, I removed lines like import views.Application._

Then with imports fixed up I could then fix up the actual controller code to return an Action and
adding Ok(views.html. … )
e.g. from
def index = {
html.index()
}

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

As I mentioned earlier, some changes to controllers were needed because the routes file now supplies default parameters, and I took out some use of the Option[T] type — though as this was generally a String, the empty string works very well as an equivalent to None.

In some controllers I’ve implemented an OAuth callback to read from a Google Calendar – eventually I’d like to play with the built-in OAuth support in Play 2 but in the interest of getting things working quickly I wanted to port over my current code. In order to send a url for Google auth to use as a callback I am calling Router.getFullUrl() but this doesn’t work in Play 2, instead one calls the automatically generated route classes instead. To turn this into a full url you call .absoluteUrl(), but you must remember to add the implicit request to your controller code in order to give this the context needed to generate the url.
e.g. the original code was approximately:

object MyController extends Controller {
  def request = {
    val callbackUrl = Router.getFullUrl(“MyController.callback”)
    // send web request using callbackUrl
  }

  def callback = {
    // handle request
  }
}

the new Play 2 code is:

object MyController extends Controller {
  def request = Action { implicit request =>
    val callbackUrl = routes.MyController.callback().absoluteURL()
    // send web request using callbackUrl
  }

  def callback = Action {
    // handle request
  }
}

This is more robust because that reverse-lookup is now checked at compile time, rather than runtime. However if your code doesn’t build, your IDE will give you errors as the reverse routes don’t exist. I did occasionally have to do a clean build to force regeneration of reverse-lookups, if the code structure had changed significantly.

Migrating Views

I had to replace @asset() with @routes.Assets.at()

Old references to actions can now be replaced with the compile-time checked generated routing objects. But the snag that isn’t documented is that if you are using a sub-project, the routes are generated within the scope of that sub-project.

e.g. replace @action(svn.Sizes.index()) with @controllers.svn.routes.Sizes.index()
This was mentioned on the Play discussion group here.

Migrating Tests

Unfortunately the bundled Play test framework has changed from scalatest to specs2. I could possibly have set up scalatest to work but decided to migrate the tests instead as the new functional tests look useful, as is the ‘property’ support in specs2.

A few imports change – I had to get rid of the scalatest imports and add in:

import org.specs2.mutable._
import play.api.test._
import play.api.test.Helpers._

The test class now simply extends Specification and I had to fiddle around with the syntax, replacing it with a noun and adding some more braces. should be(x) was replaced with mustEqual x

For example:

it should "retrieve svn server prefix" in {
  val svnServers = SvnServer.find().list()
  svnServers.length should be > (0)
}

becomes:

"SvnServer" should {
  "retrieve svn server prefix" in {
    val svnServers = SvnServer.find().list()
    svnServers.length must be_>(0)
  }
}

There is a good list of all the matchers in specs2 at the specs2 site which I found very useful.

I migrated some very basic selenium tests to the new functional test framework – documented here. The advantage of this is that you can separately test the controller, view and the whole thing together with the router.

The old selenium test was

#{selenium 'Home page'}
// Open the home page, and check that no error occured
open('/')
assertNotTitle('Application error')
#{/selenium}

So a simple test that the home page works is:

class ApplicationTest extends Specification {

  "The Application" should {
    "render template correctly " in {

      val html = views.html.Application.index()

      contentType(html) must equalTo("text/html")

      val content = contentAsString(html)
      content must contain ("Welcome to the Tools website")
      content must not contain ("Application error")
    }

    "have a working controller" in {
      val result = controllers.Application.index()(FakeRequest())

      status(result) must equalTo(OK)
      contentType(result) must beSome("text/html")
      charset(result) must beSome("utf-8")

      val content = contentAsString(result)
      content must contain ("Welcome to the Tools website")
      content must not contain ("Application error")
    }

    "run in a server" in {
      running(TestServer(3333)) {

        await(WS.url("http://localhost:3333").get()).status must equalTo(OK)

      }
    }
  }
}

Migrating the Database Models – problems!

Now for the bad news… our database models were making heavy use of the Magic[T] class and that simply isn’t present in Play 2.0 at the moment (Apparently it featured in a beta version but was removed). What Magic[T] did was generate a lot of the code for the CRUD operations from a simple case class. For reference in the old documentation for the play-scala-0.9.1, this is what Magic did.

Whilst I could write all of this code myself, I have about 40 classes to do this for, so this is a non-trivial amount of work.

I also discovered that the DB evolution hashes are different, so play wanted to revert and re-apply all of my DB schema changes, which would have trashed the DB contents. Apparently this is now fixed in the trunk in Play 2 so hopefully that change will be in a release soon.

Because I don’t have the time to rewrite all the DB classes, I decided to split my application into two parts, as there are a number of very independent reports in the site which do not use the DB. The reports will be in a play 2 site and the older code that uses the DB will stay as a Play 1.2 site.

In the future I would like to port everything to Play 2. I’m hoping that someone will reintroduce Magic[T], either into the core of Play 2 or as an additional bit of code / plugin. Alternatively I’ll have to do all the grunt work myself, which would be a shame. It’s the kind of work I like to avoid simply because there is very little value I can add – it will either keep working or (more likely) I will break something! So the best option is to leave this old ‘legacy’ site as play 1.2 until there is an easier/safer upgrade path.

However, I will definitely be using Play 2.0 for new development!

Scala at Mind Candy

Reading some recent negative commentary about Scala with interest I felt like it would be good to share our experiences with Scala.

The Good.

Scala is an expressive language – It often results in a lot less code getting in the way of what you want to do or achieve. The simple example for something like this would be a simple bit of code like this:

case class Person(id: Int, name: String)
def lookupPerson(id: Int): Person = {
  new Person(id, "Test" + id)
} // Token implementation for the example.
val ids = Seq(1,10,100)
ids.filter(id => id < 50).map(lookupPerson)

To write this in Java would require a whole load of boilerplate, which includes the case class generating the stock class methods like toString, multiple lines to create a collection and then transforming a collection.

More powerful ways to write tests – This can fall under the Spiderman grouping of power admittedly, but libraries like specs2 and scalacheck make it easier to create the kind of tests we wanted. Scalacheck is the stand-out example of this where a generator for creating Person objects from above is as easy as this:

object TestGenerators {
  val personGenerator = for {
    id <- arbitrary[Int]
    name <- alphaStr
  } yield new Person(id, name)
}

That’s all it takes and that object can be imported into all of your test code that needs to generate Person objects.

Less magic – A lot of libraries like Spring and Hibernate need to use byte code modification or reflection to achieve what they do, which means that when they fail it can be really hard to diagnose or fix the problems. We’ve even seen some of these do things non-deterministically, which has caused hours of bemusement. Contrary to this, Scala libraries just tend to use the type system to achieve these ends which means that in our case we catch problems at compile-time, not at run-time.

The REPL – The idea scratchpad and general utility will be your friend in times of need. Use this as an education tool to step through an idea with some else. Use it to test some code interactively if you want to confirm something but you’re not quite sure how to code it or what results you’ll get. Use it to solve those gnarly Project Euler problems without having to create a whole new build for each one.

SBT – Controversial one this may be, but it manages to give you the sensible build model and plugin system that Maven has while allowing you to easily create custom tasks. If nothing else being able to run a command, for example the ‘test’ task, on each save is the most useful thing I’ve seen in a while.

POWAH! – There’s an elegance that comes with time when using Scala, in much the same way that it does with a lot of languages, that means code slots together so cleanly and with little friction. For me personally the Option class was the beginning of this change in thinking, where I realised that representing the possible lack of something without using a null made a lot more sense.

The Bad.

SBT – It’s a double edged sword in you’ll need to understand a bit of Scala to be able to do non-trivial configuration in it. Documentation for this has improved massively in recent times, it can still be somewhat impenetrable, especially to someone new to Scala.

Somewhat idiomatic libraries – Databinder Dispatch is a good example of this, writing a custom handler to parse a HTTP response is just unnecessarily puzzling. As with all libraries how easy they are to use and extend should be evaluated, so don’t be blinded by those libraries just because they’re written in Scala. It’s better to pimp a stock Java library that already works well than to use one that is badly written in Scala.

Binary compatibility – This is the stock issue that is often complained about, fortunately SBT does notice when two versions of the same library that relate to two different Scala versions are pulled into the dependencies. The way others have presented this is as a major pain point, it’s generally only so much of an issue as it is with Maven dependencies with a little more granularity. Also if you’re using SBT it’s possible to create dependencies that tie to the Scala version used automatically.

Knowledge – There’s a couple of aspects to this. The first is that Scala is a “new” language and as such there is one learning curve which relates to the language, SBT, the libraries and how to use them all effectively. Beyond this is that some functional programming concepts are foreign to a lot of programmers and this can be a wall that isn’t scalable in a short period of time for a lot of people. Hopefully with time this will become less of an issue but at the moment there aren’t a lot of Scala developers that can hit the ground running.

The Ugly?

As with all new things, there is a learning curve with Scala, which can be problematic, but the benefit of the design is that it’s possible to do something the “wrong way” as the language is very flexible. People with a history in languages like Java can start out writing code that looks not that much different but still get benefits like better collections. Then with time progress onto using more the powerful features in the language like pattern matching and implicits. For the foreseeable future Scala is a tool we intend to keep using, as it’s been of great benefit to us (this week I parsed a 37GB log file with a couple of lines of code in the REPL), maybe you should too…