Deploying To Heroku
- Prerequisites
- Preparing Your Alpas App
- Preparing Your Heroku Environment
- Deploying and Running Migrations
- Subsequent Deployments
- Troubleshooting
These instructions will step you through the requirements to deploy an existing Alpas app to Heroku.
Prerequisites
- A basic Alpas app running locally with a MySQL database connection, checkout the Quick Start Guide to get your first Alpas up and running.
- A Heroku account as well as the Heroku CLI Tools installed
Preparing Your Alpas App
Adding Additional Files
Heroku reads from a special Procfile
to run your application which should be in the root of your project. This file should contain the command to execute the project's jar file:
web: java -jar ./myApp.jar
Additionally, you need a system.properties
file which will specify for Heroku the Java Runtime Environment (JRE) that is required to run the project:
java.runtime.version=1.9
Heroku randomly assigns a port in its environment to serve your app from. This is available from the system environment variable PORT
but you won't know what it is until runtime, so you can't store it as a concrete environment variable. Instead, the following allows you to read what the port number is when running and allow your app to be served up there, defaulting to port 8080 in your local environment:
package com.example.myApp.configs
import dev.alpas.AppConfig
import dev.alpas.Environment
@Suppress("unused")
class PortConfig(env: Environment) : AppConfig(env) {
override val appPort = env("PORT", 8080)
}
Altering Existing Files
Ensure that you are using Alpas version >=0.16.3
since this allows you to explicitly set the APP_HOST
variable
(required later). Check the following and update accordingly in your build.gradle
file:
ext.alpas_version = '0.16.3'
Alpas needs a .env
file in the production environment to run migration scripts amongst other processes. Modify the start.kt
file to create an empty one in your route directory if it doesn't exist whenever the main
app function is invoked:
package com.example.myApp
import dev.alpas.Alpas
import java.io.File
fun main(args: Array<String>) {
val file = File(".env")
if (!file.exists()) {
file.createNewFile()
}
return Alpas(args).routes { addRoutes() }.ignite()
}
Finally, go ahead and rebuild your project ./alpas jar
Preparing Your Heroku Environment
Configuring the Environment
You're now ready to set up your Heroku environment:
heroku create
This will create an app in your account and set it as a remote for this project. Logging into your account via the browser
navigate to the App > Settings
section and click on Reveal Config Vars
.
You will now be able to add in all the contents of your .env
file. Note, you can also do this via the command line with heroku config:set {KEY}="{VALUE}"
. Some additional important variables to add:
APP_HOST = 0.0.0.0
This binds your app to run on0.0.0.0
rather than localhost (127.0.0.1
) which is essential for Heroku. Remember, you need to be using Alpas 0.16.3 or greater to get this to work.GRADLE_TASK = shadowJar
This tells Heroku how to build your gradle project.
Some variables will need to be altered/removed compared to your .env
file:
- Any of the
DB
configs - these can be added once you have provisioned a database on Heroku. APP_PORT
- this should not be added as you are now dynamically deriving this from ourPortConfig.kt
file.APP_LEVEL = prod
this will put your app into production mode.
Setting Up MySQL
On Heroku navigate to Resources
and search for MySQL. Heroku supports a number of MYSQL database providers. Once installed click on the add-on in Heroku, this will take you to its dashboard page which has some important information:
- The host URL
- The username - note this will most likely not be root and be automatically provisioned
- The password
- The database name - some free tier MySQL plans automatically create one for you and you cannot create additional databases without upgrading to a paid plan
- The port number
Add these keys to your Heroku Settings > Config Vars
with the following values:
DB_HOST = {The host URL}
DB_CONNECTION = mysql
DB_DATABASE = {The database name}
DB_PORT = {The port}
DB_USERNAME = {The username}
DB_PASSWORD = {The password}
Deploying and Running Migrations
You are now ready to deploy to Heroku! Make sure you have a compiled jar file in your project root:
./alpas jar
Then deploy your app to Heroku by pushing your repository:
git push heroku master
Heroku will then detect that it needs to install the right JDK version (as per our system.properties
file) and build a gradle project as per the shadowJar
value we gave it earlier. This should be up and running at your designated Heroku url.
In order to successfully migrate on the free tier of Heroku, you need to temporarily bring down your app as there is not enough RAM on the dyno to both serve the app and run the migration:
heroku ps:scale web=0
Then run the migration on Heroku:
heroku run ./alpas db:migrate
Once that has successfully executed you can then bring back up the app
heroku ps:scale web=1
Refreshing your browser should bring up your home page and you are up and running in Heroku!
Subsequent Deployments
Having successfully deployed to Heroku, future deployments follow three simple steps:
- Commit your changes and recompile the project
./alpas jar
. - Run
git push heroku master
to deploy to Heroku. - If any migrations are required, follow the migration steps above.
Troubleshooting
You may find that the migration exits too early because the dyno capacity on the free tier has been maxed out. If this happens try making a trivial change to your project to force a new deploy (with the Heroku web process set to 0), navigate to App > More > Restart All Dynos
to reset the box. Then try to run the migration command.
Alternatively try App > More > Restart All Dynos
followed by heroku ps:scale web=0
to ensure that the app is not running when trying to run a migration.
Migrating with the Compiled Project
If the problem persists, you will need to run the db:migrate
command on the compiled jar file. The normal alpas
script recompiles the entire project before running the migration which likely requires too much RAM for the lower/free tier dynos.
- Create a new
alpas_prod.sh
file in the root of your project. - Copy and paste in the contents of this sample file into your
alpas_prod.sh
file. This is very similar to the originalalpas
script but runs against the already compiled jar file rather than using gradle commands which recompile the project. Be sure to rename the jar file reference in the script to your project's jar file after copying over. - As per the original
alpas
script, make sure this new file has executable rights withchmod +x ./alpas_prod.sh
. - Step through Deploying and Running Migrations above, substituting
heroku run ./alpas_prod.sh db:migrate
in for the migration command. This will execute the migration without recompiling the project.