-
Notifications
You must be signed in to change notification settings - Fork 0
Step 13 deploy to heroku
Purpose: in this step we will see how to deploy you app to heroku's cloud computing platform.
cd ~/devel/apps
git clone git@github.com:opensas/play-demo.git
git checkout origin/13-deploy_to_heroku
Creating an account at heroku is really easy. Go to Heroku homepage and click on signup to create a new account and then enter a valid email address.
follow these instructions to add heroku tools on linux.
On ubuntu, execute the following command to add heroku's repository
sudo apt-add-repository 'deb http://toolbelt.herokuapp.com/ubuntu ./'
curl http://toolbelt.herokuapp.com/apt/release.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install heroku-toolbelt
You might have to install curl first
sudo apt-get install curl
Now check that the client was successfully installed
heroku version
heroku-gem/2.8.0
heroku update
-----> Updating to latest client... done
At the command line, issue the following commands
heroku login
Enter your Heroku credentials.
Email: open@gmail.com
Password:
Here you have to enter your heroku password, do not confuse it with you private key password.
If you don't have any private/public key in ~/.ssh, it will create a new pair of keys
Could not find an existing public key.
Would you like to generate one? [Yn] Y
Generating new SSH public key.
Uploading ssh public key /home/sas/.ssh/id_rsa.pub
In order to work with heroku, first you have to create a git file.
You will have to install git on you development station. In ubuntu is as easy as
sudo apt-get install git
. Have a look at github documentation for linux and windows instructions.
First of all, make sure you are at the root of your application. Then create a .gitignore file. Here you have a handy play .gitignore template
.gitignore
# Extracted from https://github.com/ulrich/macaron-factory/blob/master/.gitignore
# Ignore all dotfiles...
.*
# except for .gitignore
!.gitignore
# Ignore Play! working directory #
db
eclipse
log
logs
precompiled
tmp
test-result
eclipse
server.pid
Now run the app in production mode to test it
play run --%production
And then create the git repo and issue an initial commit
git init
git add .
git commit -m init
[master (root-commit) 93e6f9d] init
16 files changed, 391 insertions(+), 0 deletions(-)
create mode 100644 .gitignore
create mode 100644 app/controllers/Application.java
create mode 100644 app/views/Application/index.html
create mode 100644 app/views/errors/404.html
create mode 100644 app/views/errors/500.html
create mode 100644 app/views/main.html
create mode 100644 conf/application.conf
create mode 100644 conf/dependencies.yml
create mode 100644 conf/messages
create mode 100644 conf/routes
create mode 100644 public/images/favicon.png
create mode 100644 public/javascripts/jquery-1.5.2.min.js
create mode 100644 public/stylesheets/main.css
create mode 100644 test/Application.test.html
create mode 100644 test/ApplicationTest.java
create mode 100644 test/BasicTest.java
create mode 100644 test/data.yml
Now we'll create the new app on heroku
heroku create -s cedar
Creating afternoon-dusk-4670... done, stack is cedar
http://afternoon-dusk-4670.herokuapp.com/ | git@heroku.com:afternoon-dusk-4670.git
Git remote heroku added
Heroku will automatically pick a name for you application in this case it was afternoon-dusk-4670.
And will issue our initial deploy:
git push heroku master
That's it! A deploy to heroku is just a git push away...
When pushing to git, you'll have to enter you password to the private key created in ~/.ssh, do not confuse with your heroku key.
Always before deploying you have to commit your changes on the master branch
Now you can point your browser to http://afternoon-dusk-4670.herokuapp.com or just issue heroku open
to let heroku do that for you.
It's highly probable that you won't like afternoon-dusk-4670, so navigate to https://api.heroku.com/myapps, click on afternoon-dusk-4670, and change it's name to play-demo-test. The following message will appear:
afternoon-dusk-4670 renamed to play-demo-test.
Existing git checkouts must be updated.
Follow these instructions:
git remote rm heroku
git remote add heroku git@heroku.com:play-demo-test.git
Now you can check you app at http://play-demo-test.herokuapp.com
We'll have to make a couple of changes so that our app con work flawlessly on heroku. For that purpose we'll first see a few commands that will let us deal with heroku.
heroku info
=== play-demo-test
Web URL: http://play-demo-test.herokuapp.com/
Git Repo: git@heroku.com:play-demo-test.git
Dynos: 0
Workers: 0
Repo size: 42M
Slug size: 26M
Stack: cedar
Data size: (empty)
Addons: Basic Logging, Basic Release Management, Shared Database 5MB
Owner: opensas@gmail.com
heroku config
DATABASE_URL => postgres://xxx:yyyy@zzz/wwww
JAVA_OPTS => -Xmx384m
PATH => .play:.tools:/usr/local/bin:/usr/bin:/bin
PLAY_OPTS => --%prod -Dprecompiled=true
SHARED_DATABASE_URL => postgres://xxx:yyyy@zzz/wwww
heroku releases
Rel Change By When
---- ---------------------- ---------- ----------
v5 Deploy a4776ec opensas@gmail.com 8 minutes ago
v4 Config add PLAY_OPTS, PATH, .. opensas@gmail.com 8 minutes ago
and the most important command heroku logs. This command will let us inspect heroku's execution logs. We will have to study them carefully to see what's going on on the server. For example. here's the output when we try to execute BootstrapJob.
heroku logs
...
2011-09-20T14:05:40+00:00 app[web.1]: 14:05:40,511 ERROR ~ ERROR: current transaction is aborted, commands ignored until end of transaction block
2011-09-20T14:05:40+00:00 app[web.1]: 14:05:40,511 ERROR ~ While deleting class models.Event instances
2011-09-20T14:05:40+00:00 app[web.1]: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute update query
2011-09-20T14:05:40+00:00 app[web.1]: at
...
p[web.1]: at play.test.Fixtures.delete(Fixtures.java:72)
Most modifications you'll have to make to your app comes from the fact that Heroku uses postgresql database. So you should install postgresql on your workstation to be able to spot problem when developing the app.
Follow this guide to install postgresql on ubuntu, or just issue
sudo apt-get install postgresql pgadmin3
Run pgadmin and create a play-demo database and a play-demo-account account, with full permissions to that db. These are the sql commands generated by pgadmin.
-- create database
CREATE DATABASE "play-demo"
WITH ENCODING='UTF8'
CONNECTION LIMIT=-1;
-- create a new group role play-demo-role
CREATE ROLE "play-demo-role"
VALID UNTIL 'infinity';
-- create a new login role play-demo-login with password: play-demo-pass
-- and in role membership add play-demo-role
CREATE ROLE "play-demo-login" LOGIN ENCRYPTED PASSWORD 'md577e4b34d0ac90d3047950899a76fb04f'
VALID UNTIL 'infinity';
GRANT "play-demo-role" TO "play-demo-login";
-- grant permissions to play-demo-role on play-demo database
GRANT ALL ON DATABASE "play-demo" TO GROUP "play-demo-role";
Now you'll have to modify your application.conf to change the database we are using on development and production mode. So comment the db=mem line, add our local database configuration, and set the prod configuration to point to the environment variable SHARED_DATABASE_URL.
Your application.conf file should be like this:
# - fs : for a simple file written database (H2 file stored)
# db=mem
[...]
# heroku configuration
%prod.db=${SHARED_DATABASE_URL}
# local development configuration
# If you need a full JDBC configuration use the following :
db.url=jdbc:postgresql:play-demo
db.driver=org.postgresql.Driver
db.user=play-demo-login
db.pass=play-demo-pass
See these two articles for more information on configurating your database for heroku
http://www.touilleur-express.fr/2011/09/19/deployer-play-framework-heroku/
http://devcenter.heroku.com/articles/database-driven-play-apps
You'll also have to enable sql statements debug on play. Edit application.conf file an uncomment the following line
conf/application.con
# Debug SQL statements (logged using DEBUG level):
jpa.debugSQL=true
Now start your app and check the console output:
You should see the following line
11:40:12,742 INFO ~ Connected to jdbc:postgresql:play-demo
11:40:18,506 ERROR ~ Unsuccessful: create table User (id int8 not null, accessToken varchar(255), avatarUrl varchar(255), name varchar(255), secret varchar(255), token varchar(255), primary key (id))
11:40:18,507 ERROR ~ ERROR: syntax error at or near "User"
Just put the table name between apostrophes "" so that postgresql can refer to the table. Add the @Table annotation to User model.
models.User
@Entity()
@Table(name="\"User\"")
public class User extends Model {
Then restart the app.
When executing the BootstrapJob for the first time everything works fine, but the second time you'll see the following error on the console:
11:44:32,433 WARN ~ SQL Error: 0, SQLState: 23503
11:44:32,435 ERROR ~ ERROR: update or delete on table "eventtype" violates foreign key constraint "fk403827aa2ebda90" on table "event"
Detail: Key (id)=(1) is still referenced from table "event".
11:44:32,444 ERROR ~ While deleting class models.EventType instances
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute update query
When it tries to delete the EventTypes, if finds Events associated with them.
Just modify BootstrapJob to delete the Entities in an order that prevents foreign key violation from happening. And at the same time will add some logging.
@Override
public void doJob() {
//forces orm to delete first the events
Fixtures.delete(Event.class);
Fixtures.delete(EventType.class);
Fixtures.delete(User.class);
// just to be sure, now delete all models
Fixtures.deleteAllModels();
Fixtures.loadModels("data.yml");
Logger.info("ran BootstrapJob, %s events loaded, %s types loaded", Event.count(), EventType.count());
}
Now start the app again and reload the events from the yaml file a couple of times.
Our app will be on the cloud running, for everyone to create and update events. We don't want to run out of events, so will schedule a job to recreate data every 30 minutes. It's very easy to do that with play, jue add the @Every annotation to the job.
lib.utils.BootstrapJob
[...]
@OnApplicationStart
@Every("30min")
public class BootstrapJob extends Job {
@Override
public void doJob() {
[...]
And we will also add a legend telling the user that the info will be reloaded.
views/Application/list.html
[...]
<div class="page-header">
<h1>
&{'event.title'}
<small>&{'event.flashData'}</small>
</h1>
</div>
[...]
And of course, define event.flashData in messages.en and any other locale you support.
event.flashData=(demo application, data will be flashed every 30 minutes)
Tip: with the command git status you can see the changed files
git status
# On branch master
# Your branch is ahead of 'origin/master' by 11 commits.
#
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: app/lib/jobs/BootstrapJob.java
# modified: app/views/Application/list.html
# modified: app/views/partials/topbar.html
# modified: conf/application.conf
# modified: conf/messages
# modified: conf/messages.en
# modified: conf/messages.es
add every file to the next commit
git add .
git commit -m "troubleshooted heroku, flash data every 30 min"
and now deploy
git push heroku master
And that's it, now your application is up and running in heroku.
http://devcenter.heroku.com/articles/play
http://toolbelt.herokuapp.com/linux/readme
http://www.jamesward.com/2011/08/29/getting-started-with-play-framework-on-heroku
Now we are going to Step 14 - deploy to gae.