Deploying to Heroku
Heroku is a cloud application platform that makes it easy to deploy and scale applications. With the right project setup, deploying your application becomes as easy as git push
.
1. Sign up for a free a free account.
2. Install the Heroku CLI.
3. Set up a project.
Create a Scalatra project from the usual Scalatra giter8 template. Check out the installation and first project guides if this isn’t familiar.
$ sbt new scalatra/scalatra.g8
4. Tweak the app for Heroku
Make Jetty embeddable
Open build.sbt
in the root of your project. You will find a line like this:
"org.eclipse.jetty" % "jetty-webapp" % "9.4.8.v20171121" % "container",
Those are basically right, but we need to add compile
scope because Heroku is not a servlet host. It can only run your app via an embedded Jetty server you provide. So replace the line above with this one:
"org.eclipse.jetty" % "jetty-webapp" % "9.4.8.v20171121" % "compile;container",
Add the sbt Native Packager plugin
You don’t want to use sbt to run your app in production. We’ll install an sbt plugin that will create a start script during compilation. Heroku will use that start script. Tell sbt where to find the plugin by adding this line to project/plugins.sbt
(you may need to create the file first):
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.2")
Then enable the plugin by calling the enablePlugins
method in your build.sbt
:
enablePlugins(JavaAppPackaging)
Create a main
method
Since Heroku launches your app without a container, you need to create a main
method that launches the servlet.
Create src/main/scala/JettyLauncher.scala
with this code:
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.{ DefaultServlet, ServletContextHandler }
import org.eclipse.jetty.webapp.WebAppContext
import org.scalatra.servlet.ScalatraListener
object JettyLauncher {
def main(args: Array[String]): Unit = {
val port = if(System.getProperty("http.port") != null) System.getProperty("http.port").toInt else 8080
val server = new Server(port)
val context = new WebAppContext()
context.setContextPath("/")
context.setResourceBase("src/main/webapp")
context.setEventListeners(Array(new ScalatraListener))
server.setHandler(context)
server.start
server.join
}
}
And don’t forget to set your servlet mapping (you probably already have something like this in ScalatraBootstrap
):
context.mount(new MyScalatraServlet, "/*")
If you have a custom bootstrap class location:
context.setInitParameter(ScalatraListener.LifeCycleKey, "org.yourdomain.project.MyScalatraBootstrap")
Tell Heroku how to run your app (optional)
Heroku will detect the target/universal/stage/bin/<app-name>
script generated
by sbt-native-packager, so it will know how to run your app by default.
However, you may want to customize how your app starts. In that case, create
a Procfile
with contents such as:
web: target/universal/stage/bin/<app-name> -Dhttp.port=$PORT -Dother.prop=someValue
And replace <app-name>
with the name of your app defined in build.sbt
.
5. Deploy
If you haven’t set up your project as a Git repo, do so.
$ cd [app root]
$ chmod u+x sbt
$ git init
$ git add .
$ git commit -m 'first commit'
Log into Heroku.
$ heroku login
Create your Heroku endpoint and deploy to it.
$ cd [app root]
$ heroku create
$ git push heroku master
After a couple minutes of streaming output, the last few lines will look like this:
-----> Discovering process types
Procfile declares types -> web
-----> Compiled slug size: 43.4MB
-----> Launching... done, v5
http://polar-atoll-9149.herokuapp.com deployed to Heroku
To git@heroku.com:polar-atoll-9149.git
* [new branch] master -> master
Open your browser to to the URL provided right before deployed to Heroku
in the output. Or just run:
$ heroku open
For more information on using Scala with Heroku see the Heroku DevCenter.