Fun with Catalyst and Heroku
For my first experiments with heroku I decided to adapt an existing Catalyst application…
Create and deploy the application
The first step is to create a new heroku app: since I already have a git repo I just added the heroku remote with heroku git:remote --app myapp
.
I decided to use Miyagawa’s buildpack which runs any PSGI web application using Starman.
$ heroku buildpacks:set https://github.com/miyagawa/heroku-buildpack-perl
I need an app.psgi in the root of the application to use this buildpack. This is how my .psgi file looks like
#!/usr/bin/env perl
use lib 'lib';
use MyApp;
use Plack::Builder;
builder {
enable_if { $_[0]->{HTTP_X_FORWARDED_FOR} }
"Plack::Middleware::ReverseProxy";
MyApp->psgi_app;
};
I’m using Plack::Middleware::ReverseProxy
here since Heroku apps run as a reverse proxy backend.
When pushing code to heroku you can see how the buildpack detects the application and downloads the required software from CPAN.
$ git push heroku
[snip]
remote:
remote: -----> Fetching custom git buildpack... done
remote: -----> Perl/PSGI app detected
remote: -----> Bootstrapping cpanm
remote: Successfully installed ExtUtils-MakeMaker-7.04 (upgraded from 6.55_02)
[...]
Postgres database
A basic Posgres database can be created using heroku addons:create heroku-postgresql:hobby-dev
: to use it I needed to install DBD::Pg
and configure the DBI connection.
Since my cpanfile contains an optional feature for adding Postgres support.
feature 'postgres', 'PostgreSQL support' => sub {
requires 'DBD::Pg';
}
I instructed the buildpack to install the optional module just by using
heroku config:set PERL_CPANM_OPT=--with-feature=postgresql
.
Note: PERL_CPANM_OPT
can also be used to add any additional parameter to cpanm, e.g. use —mirror for a PINTO repo.
All the parameters I needed configure the database connection are in the DATABASE_URL heroku variable, however this cannot be directly used by Catalyst. A nice way to pass them is to create a specific Catalyst configuration file, however in this case I didn’t want to add anything specific for heroku in my repo and I opted for to injecting them to the default configuration using environment variables.
In my MyApp.pm
I have added these defaults for connect_info:
__PACKAGE__->config(
'Model::MyApp' => {
connect_info => [
$ENV{MYAPP_DB_DSN} || 'dbi:SQLite:myapp.db',
$ENV{MYAPP_DB_USERNAME},
$ENV{MYAPP_DB_PASSWORD},
{ AutoCommit => 1 },
{ quote_names => 1 },
],
});
The variables can be set using the heroku config:set command
heroku config:set 'MYAPP_DB_DSN=dbi:Pg:dbname=xxxx;host=xyz123.amazonaws.com' MYAPP_DB_USER=aabbbccc MYAPP_DB_PASSWORD=wwwyyyzz
Make sure you’re not using memory or file backend for session storage, always use your DB or other storage backend (e.g. Redis).
Leave a comment