Grails on Heroku

[Note: The Information in the following post is out of date. Please use the Grails Heroku plugin instead ( edited Dec 19, 2011 )]

Heroku recently announced Java support. In this post, I will show you how to deploy Grails applications into Heroku using the Maven support available to Grails.

Heroku recommends building a jar file and executing this against an embedded Jetty instance. This solution simply does a simple grails run-app and is inspired by the Play! framework support in Heroku. ( BTW, why Roo & Play! and not Grails? )

Updated Sept. 02 – using jetty runner in the example.

Prerequisites

1. Install the Heroku package bundles in your local machine.

Follow the instructions here: http://devcenter.heroku.com/articles/java#local_workstation_setup

2. Get your credentials by signing up for an account at http://www.heroku.com

3. Associate your credentials via ‘heroku login’ in a terminal window.


deathstar:grails-heroku-sample tomaslin$ heroku login
Enter your Heroku credentials.
Email: tomaslin@gmail.com
Password:
Found existing public key: /Users/tomaslin/.ssh/id_rsa.pub
Would you like to associate it with your Heroku account? [Yn] y
Uploading ssh public key /Users/tomaslin/.ssh/id_rsa.pub

4. Install Foreman

gem install foreman

5. Install Maven if you don’t have it.

Follow the instructions at http://maven.apache.org/download.html

You might also want to set a MAVEN_OPTS environment variable to handle the amount of memory grails uses to build –

export MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=192m"

6. Install Grails if you don’t have it

Follow the instructions at http://www.grails.org/Installation

Building a Heroku grails project

1. Create your grails project

In a console, type

grails create-app grails-on-heroku

2. Convert this into a Maven project

We convert the grails project into a Maven project because this is usually less of a pain. Refer to section 4.5 of the grails user guide if you want to have other workflows.

In terminal, type:

mvn org.grails:grails-maven-plugin:1.3.7:create-pom -DgroupId=com.tomaslin

where groupId is the package name for your company.

Maven will proceed to download the entire Internet ( or so it seems ). But at the end of this process, you should have a sexy sexy Pom.xml file.

3. Define a Procfile

Create a file on the root of the application named Procfile.

Add the following into it:

web: mvn -Dserver.port=$PORT grails:run-app

Add the following into it:

  web: java $JAVA_OPTS -jar target/dependency/jetty-runner.jar --port $PORT target/*.war  

4. Uncomment mavenCentral() and mavenLocal()

You probably also want to uncomment the mavenCentral() and mavenLocal() repos from grails-app/conf/BuildConfig.groovy

5. Add reference to jetty-runner in your pom.xml file.

Add this to your pom.xml’s build section ( see Graeme’s comment on this post for a link )

<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>copy</goal></goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-runner</artifactId>
<version>7.4.5.v20110725</version>
<destFileName>jetty-runner.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>

Deploying your sexy beast

In a console, type


git init

git add .

git commit -a -m init

heroku create --stack cedar

git push heroku master

If you type heroku open, you won’t see anything since your application is deployed against /grails-on-heroku. You can change the context path if you would like to see it in root.

You can use the command heroku logs to see the deployment process.

You end up with a deployed application like this:

http://hollow-spring-928.herokuapp.com/grails-on-heroku/

Observations

  • The hibernate plugin seems to crash and burn in maven. The temporary solution was to uninstall the plugin. This might have to do with the inclusion of the pom file of a stale jBoss repo. Or it could be completely unrelated.
  • Heroku seems to do a mvn:install on every deployment. Might be easy to remove this.
  • In my digging, came across these posts that might be helpful:
  • Compared to CloudFoundry ( which still doesn’t have a price sticker ), Heroku is very nice. Having their servers build the war files definitively feels faster and more productive.
  • Originally started trying to do a grails run-war, but it seems that server.port is not passed in correctly to this.
  • This is not production ready, you should never run production with grails run-app.
  • Heroku doesn’t seem to accept polyglot projects. If it detects that something is a clojure project, it will ignore the Java POM. This whole fiasco would have been easier if we could have used herokujetty and mvn:pom.

21 thoughts on “Grails on Heroku

    1. Chanwit Kaewkasi

      With this example, it seems to be a ‘hard’ way, doesn’t it?
      Correctly if I am wrong. The pom.xml in the example is manually written?
      If so, I am wondering how can I obtain a complete pom.xml out-of-the-box before deploying to Heroku.

      Reply
  1. Pingback: Pedro Newsletter 01.09.2011 « Pragmatic Programmer Issues – pietrowski.info

  2. williamcheungdev

    In the pom created by the grails-maven-plugin, I had to change the scope of slf4j from runtime to compile to get my app to start on Heroku. Otherwise, I got:

    java.lang.IllegalAccessError: tried to access field org.slf4j.impl.StaticLoggerBinder.SINGLETON from class org.slf4j.LoggerFactory

    Reply
    1. andres

      I tried that but is still failing i changed the pom slfj4 to compile, can you provide more tips around that, maybe your pom.xml (i would love to have a clean one, cause it downloads the internet)

      Reply
  3. Phil Haigh

    I ran through this using Groovy 1.8.2 and Grails 1.3.7. It worked flawlessly except that I had to add some dependencies to BuildConfig.groovy:

    runtime ‘antlr:antlr:2.7.6’
    runtime ‘commons-collections:commons-collections:3.1’
    runtime ‘org.slf4j:slf4j-api:1.5.2’

    The only other thing I noticed was that the application was deployed to the root, rather than to a URI matching the name of the project. Nice one!

    Reply
  4. Pingback: Android, Grails and Heroku « Surfsoft Consulting Blog

  5. Lucas

    Hi! I’m really enthusiastic on your tutorial, and I think it’s very useful.
    I tried it by myself, but I get just this in the log:

    2011-10-05T23:54:46+00:00 heroku[router]: Error H14 (No web processes running) -> GET sharp-leaf-7769.herokuapp.com/ dyno= queue= wait= service= status=503 bytes=

    Do you have any clue for me? Thanks in advance!!

    Reply
    1. James Ward

      Make sure you have a Procfile that defines how to start the web process. And then try to start up a web dyno:
      heroku scale web=1

      Then check to see if it is running:
      heroku ps

      Reply
      1. James Ward

        You shouldn’t usually have to. But there are situations where Heroku won’t automatically create a default web dyno for you. I’ve seen this when I didn’t have a Procfile on my first git push.

  6. Sebastien Arbogast (@sarbogast)

    I followed the tutorial step-by-step but I’m getting the following output in heroku logs:

    2011-10-31T11:49:34+00:00 heroku[web.1]: Starting process with command `java -Xmx384m -Xss512k -XX:+UseCompressedOops -jar target/dependency/jetty-runner.jar –port 18081 target/`
    2011-10-31T11:49:35+00:00 app[web.1]: Unable to access jarfile target/dependency/jetty-runner.jar
    2011-10-31T11:49:35+00:00 heroku[web.1]: Process exited
    2011-10-31T11:49:36+00:00 heroku[web.1]: State changed from starting to crashed
    2011-10-31T11:49:36+00:00 heroku[web.1]: State changed from crashed to created

    It seems that it can’t find the jetty-runner.jar file. Yet I added the plugin sections in my POM.

    Reply
  7. Pingback: Android, Grails and Heroku » Surfsoft Labs

Leave a comment