-
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
cd play-demo
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, enter a valid email address and just follow the instructions you'll receive by mail.
Follow these instructions to add heroku tools on linux.
On ubuntu, execute the following commands 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
To manually setup you public/private keys, see the Setup Up ssh keys in this article.
In order to work with heroku, first you have to create a git repository.
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 file.
.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 we will issue our initial deploy:
git push heroku master
That's it! A deploy to heroku it's just a git push...
When pushing to git, you'll have to enter the password of the private key created in ~/.ssh, do not confuse with your heroku password.
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 jugar-demo. The following message will appear:
afternoon-dusk-4670 renamed to jugar-demo.
Existing git checkouts must be updated.
Follow these instructions:
git remote rm heroku
git remote add heroku git@heroku.com:jugar-demo.git
Now you can check your app at http://jugar-demo.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://jugar-demo.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 "jugar-demo"
WITH ENCODING='UTF8'
CONNECTION LIMIT=-1;
-- create a new group role jugar-demo-role
CREATE ROLE "jugar-demo-role"
VALID UNTIL 'infinity';
-- create a new login role jugar-demo-login with password: play-demo-pass
-- and in role membership add jugar-demo-role
CREATE ROLE "jugar-demo-login" LOGIN ENCRYPTED PASSWORD 'md577e4b34d0ac90d3047950899a76fb04f'
VALID UNTIL 'infinity';
GRANT "jugar-demo-role" TO "jugar-demo-login";
-- grant permissions to play-demo-role on play-demo database
GRANT ALL ON DATABASE "jugar-demo" TO GROUP "jugar-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:jugar-demo
db.driver=org.postgresql.Driver
db.user=jugar-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 quotation marks "" so that postgresql can refer to the table. Add the @Table annotation to User model like this:
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
Postgresql can't delete EventTypes because there are 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 running to the cloud, 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. Play supports scheduled jobs, so we'll just have to 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, we'll have define event.flashData in messages.en and any other locale you support.
conf/messages.en
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
Stage every changed file and commit 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.