« 2012年12月 | メイン | 2013年3月 »

2013年1月

2013年1月23日 (水)

HerokuのPostgreSQLをアップグレードする

こんにちは。
HerokuのPostgreSQLを9.2にアップグレードする作業を行ったのでその手順を残しておきます。

 

1、WebコンソールでアプリのオーナーアカウントのAPIキーを確認
有償Addonの追加を行うのでコマンドはアプリオーナーのアカウントで叩く必要があります。

 

2、コマンドラインでherokuアカウントの切り替え

 

set HEROKU_API_KEY=xxxxx

 

簡単なのでいつもこの方法でアカウントを切り替えてますが、ちゃんと切り替えようとするならコマンドプラグインの「heroku-accounts」を入れるのが良いらしいです。
この方法だとgitにはアクセスできないですしね。

 

3、メンテナンスモードにして外部からのアクセスを遮断

 

heroku maintenance:on --a my-app

 

4、PostgreSQLのデータバックアップ
Addonのpgbackupsを使ってデータをバックアップします。
pgbackupsは無償で毎日バックアップを取ってくれるのでPostgreSQLを使うなら必ず入れた方が良いです。

 

heroku pgbackups:capture -a my-app

バックアップを取り終わったら表示されたバックアップIDをメモしておきます。

 

5、既存のPostgreSQLを入れ替え
バックアップが終わったら既存のDBを破棄して9.2で新しいDBを作成します。

 

heroku addons:remove heroku-postgresql:crane -a my-app
heroku addons:add heroku-postgresql:crane --version=9.2 -a my-app

 

「--version=9.2」がPostgreSQLのバージョン指定です。
多分現時点ではまだ無指定の場合は9.1になると思うけど近日デフォルト9.2に変わるはずです。

DB作成時にforkオプションを指定するとを使うとDBの作成とデータの移行を同時にやってくれるはずですが、同一プランでのDBの追加ができるのかどうかがいまいち確信が持てなかったので先に既存DBを破棄してから追加しました。

DBの作成が完了するまでには数分かかるので

 

heroku pg -a my-app

 

でStatusがavailableになるのを待ちます。

 

6、データのリストアとDATABASE_URLの切り替え

 

heroku pgbackups:restore HEROKU_POSTGRESQL_XXXX_URL bxxx -a  my-app
heroku pg:promote HEROKU_POSTGRESQL_XXXX_URL -a  my-app

 

作成されたDBにバックアップをリストアします。
DATABASE_URLの切り替えは「heroku config:add」で行っても同じです。
(pg:promoteは内部的にheroku config:addを実行しているだけです。)

 

7、メンテナンスモード解除

 

heroku maintenance:off --a my-app

 

以上、動作確認して終わりです。
データ量にもよると思いますが概ね10分くらいで作業できます。

2013年1月18日 (金)

Herokuにやられた日

こんにちは。珍しくHerokuではまったのでその顛末を書いておきます。
しかも間抜けなことに同じ問題で2回はまりました。。。(--

さて、それがどういう問題だったかと言うと。。。

Procfileの行末がCRLFだとDynoが正しく起動できなくなる。

というものです。(--
これ、最初から動かなかったわけではなくて少なくとも12月の中旬ごろまでは間違いなく動いていました。
それが何かの修正のタイミングで行末がCRLFだった場合は最後のCRをコマンドの一部として実行するようになったようです。

最初から動いてなければそういうものとして納得することができるんですが、ある日突然動かなくなったので非常に焦りました。
現象の現れ方としては最初に書いたとおり2パターンありました。

 

★パターン1 - アプリが起動しない

あるアプリに1カ月ぶり位にちょっとした修正を加えてgit pushしたところいきなりアプリが起動しなくなりました。
何故かログには「NoClassDefFoundError: 」とか出力されて止まっています。
修正自体はささいなものだったので、それが原因とは考えられず最初は何が起こっているのかまったくわかりませんでした。

原因を追究するよりも先にまずはアプリを起動状態に戻さなければならなかったので修正をリバートしたものをgit pushしたんですが状況は改善しません。(--
なかば途方にくれながら今まで一度も使ったことがないコマンド「heroku releases:rollback」を使用して以前のバージョンに戻すとようやく起動するようになりました。

□□□□

話は少しそれますが、この「heroku releases:rollback」というコマンドはコンパイル済みのスラグと環境変数一式をどこかにとっておいてまるっと差し替えるコマンドのようです。
Git repository自体には手が入らないので次回にgit pushした時にはまた最新のrepositoryから新しいスラグが作成されます。(ただし環境変数はそのまま)

動作原理がわかっているといざという時に迷わず使えて便利そうではあります。抑えておいて損はないコマンドだと思います。
(途中にAddOnの追加があった場合はどうなるんだろうという疑問はありますけど。)

□□□□

さて、これでとりあえずアプリは動作するようになったわけですが、原因を調べようにもちょっとした変更をgit pushするだけでもれなくクラッシュするのでまたしても途方にくれてしまいます。(--
この時点でHerokuのサポートにあげても良かったんですが、もうちょっと自分で調べようと思い新しいHerokuアプリを作成してそっちにソース一式をpushして調査を継続することにしました。こういうことが手軽にできるのはHerokuの良いところではありますね。(と、フォローしてみる)

そんなこんなで紆余曲折、艱難辛苦の末にたどりついた原因がProcfileだったわけですが、これには本気で脱力しました。。。(--

その時のProcfileがこれ。

 

web: play run --http.port=$PORT $PLAY_OPTS <CRLF>

 

改行コードがCRLFであることと行末にスペースが入っていることがポイントです。
playコマンドの最後の引数として単独の「<CR>」が渡されていて、それがクラス名表示のないNoClassDefErrorを引き起こしていたらしい。。。。(--
マジでか!!!

HerokuがLinux上で動くプロダクトである以上、あらゆるファイルの改行コードはLFで統一すべきという指摘はもっともだと思うし、実際エディタの設定等は気をつけてはいるんですが、Procfileはすっかりechoとリダイレクトで作成する習慣がついていたので気が付かなかったんですよね。。。

先にも書きましたがこれが最初から起こっていた現象であるなら特に文句はありません。
しかし、ある日突然動かなくなったら「こんなの気づきっこねー」と愚痴のひとつも言いたくなるというものです。

結局この日はここまでで力尽きて帰りました。

★パターン2 - アプリの起動が重くなる

さて、今にして思えばこの時点ですべてのHerokuアプリのProcfileを見直しておけば良かったんですが、何しろその日はやろうと思っていたことが何一つできなかったので次の日はそれどころではありません。一応Herokuのサポートにレポートをあげたんですが、あっさりと「ごめん、直しとく」みたいな返答がきたこともあってこの問題については自分の中ですっかりかたがついてしまっていました。

そうこうしているうちに別のアプリでやけに起動に時間がかかるという問題に気が付きます。具体的には以下のような現象が発生していました。

  • git pushや環境変数の変更後ブラウザからの応答が長時間なくなる
  • ログを見るとR10(Boot timeout)がしばしば記録されている。つまりHerokuがDyno起動をリクエストした後1分間起動が完了せずに再起動を繰り返すことがある
  • たまに起動直後からR14(Memory quota exceeded)が記録されることがある。起動直後に大きなメモリを使用するような処理はないので明らかにおかしい

これも最初原因がわからなかったんですが、再起動時のログをtailで眺めていると常に「Precompiling...」というログを出力した後で一度ログの流れが止まることに気が付きました。あれ?起動時にPrecompileとかって走るんだっけ???

□□□□

で、調べてみるとPrecompileはPRODモードでかつ起動オプションに「-Dprecompiled=true」が指定されていない時に実行されることがわかりました。しかし、「-Dprecompiled=true」は環境変数のPLAY_OPTSで指定されているはず。
ということでもう一回Procfileです。

 

web: play run --http.port=$PORT $PLAY_OPTS<CRLF>

 

前のと同じに見えますか?(^^;
いえ、今回はCRLFの前にスペースがないことがポイントです。

環境変数「PLAY_OPTS」の末尾は「-Dprecompiled=true」となっていますが、これが行末のCRと結合して「-Dprecompiled=true<CR>」として引数化され、結果precompiled=trueとは解釈されないという。。。(--
またお前かよ!

実のところ2回目は問題解決にそれほど大きく時間を取られたわけではないのですが、脱力のあまりこのブログを書き始めてしまったので結局結構な時間が。。。。(--

まぁ別にいいんですけどね。(^^;;;

採用情報

株式会社フレクトでは、事業拡大のため、
Salesforce/Force.comのアプリケーション
開発
HerokuやAWSなどのクラウドプラッ
トフォーム上でのWebアプリケーション開発

エンジニア、マネージャーを募集中です。

未経験でも、これからクラウドをやってみた
い方、是非ご応募下さい。

フレクト採用ページへ

会社紹介

株式会社フレクトは、
認定コンサルタント
認定上級デベロッパー
認定デベロッパー
が在籍している、
セールスフォースパートナーです。
heroku partnersにも登録されています。
herokuパートナー
株式会社フレクトのSalesforce/Force.com
導入支援サービス
弊社の認定プロフェッショナルが支援致します。
・Visualforce/Apexによるアプリ開発
・Salesforceと連携するWebアプリ開発
も承っております。
セールスフォースご検討の際は、
お気軽にお問合せください。
Powered by Six Apart