読み書きプログラミング

日常のプログラミングで気づいたことを綴っています

Sinatra with Delayed Job on PostgreSQL 動きました!

Sinatra with Delayed Job on PostgreSQLがローカル(OS X Lion)で動きました。以下、備忘録です。

概要

Sinatra上のウェブアプリケーションにバックグラウンドジョブを実装しました。
バックグランドプロセスにはRailsプラグインとして有名なDelayed Job、バックエンド(ジョブキュー)にはActive Record、データベースにはPostgreSQLを採用しました。

データベースPostgreSQLの準備

PostgreSQLオープンソースのデータベースです。herokuがウェブアプリケーションに提供するデータベースサービスにも使われています。heroku上へのディプロイが目的なので最初からPostgreSQLを使うことにしました。
1. MacPortsからインストール
Lion(もしくはXcode for Lion)にはデフォルトでPostpreSQLがプレインストールされているようです。知らなかったので、MacPortsからインストールしました。(これがトラブルの元になりました。)

sudo port install postgresql90 postgresql90-server

インストールするとその後必要な手順も出力されますので、そのまま実行してください。(データベース用ディレクトリの作成とデーモン起動)

sudo port load postgresql90-server
sudo mkdir -p /opt/local/var/db/postgresql90/defaultdb
sudo chown postgres:postgres /opt/local/var/db/postgresql90/defaultdb
sudo su postgres -c '/opt/local/lib/postgresql90/bin/initdb -D /opt/local/var/db/postgresql90/defaultdb'

2. データベース用アカウントのパスワード変更
postgresというユーザーアカウントが作成されるので、パスワードを変更しておきましょう。

3. PATHの設定
.profileにてPATHの先頭に/opt/local/lib/postgresql90/binを追加します。
PATHを追加しないと、以下の作業で前述のプレインストールのPostpreSQLコマンドが起動して動かず悩みます。また、RubyPostgreSQL用アダプタpg gemをインストールする際にもエラーの元になります。


(ここで一度再起動が必要かもしれません。)


4. データベースユーザーの作成

su postgres
createuser

createuserの後、プロンプトが出るので質問に答えていきます。
使い分けがわからないので、ユーザー名はOSのアカウント名を一緒にしておきました。
データベースを作成できるように設定。


以上でデータベースのインストール完了です。

Ruby環境準備

Bundlerをインストールします。

sudo gem1.9 install bundle

SinatraでDelayed Jobを使う

Railsマイグレーションファイルを用意する

SinataでActive Recordを使うのにマイグレーションファイル生成などsinatra-activerecordパッケージがありますのが、 sinatra/activerecord/rakeはほとんど空っぽのマイグレーションファイルしか作ってくれませんでした。delayed_jobを指定する方法がよくわかりませんでした。なので、Railsで生成してコピーしました。
後で知ったDelayed Job (DJ)の記事に従って作るほうが筋が良さそうです。


1. Railsで新しいアプリケーションを生成します。

rails new foo--database=postgresql

2. Gemfileにgem 'delayed_job'の一行を追加して、インストールします。

bundle install

3. マイグレーションファイルを生成します。

ruby1.9 script/rails generate delayed_job


アプリケーションfooの役割はここまでです。

アプリケーション用データベースを作成する
createdb <database name>
Sinatraアプリケーションを変更する

1. アプリケーションfooのconfig/database.ymlをコピーして、データベース名など必要な修正をします。


2. アプリケーションfooのdb/migrate以下をコピーします。


3. Gemfileに以下を追加し、インストール(bundle install)を実行します。

gem 'pg'
gem 'activerecord'
gem 'logger'
gem 'delayed_job'

pgはRubyPostgreSQLアダプタです。ググるとpostgresやpostgres-prも目につきますがpgを使います。


4. Rakefileを作成します。

require 'configureを含むファイルのベース名'
require 'delayed/tasks'

task :environment

namespace :db do
  desc "Migrate the database"
  task :migrate => :environment do
    ActiveRecord::Base.logger = Logger.new(STDOUT)
    ActiveRecord::Migration.verbose = true
    ActiveRecord::Migrator.migrate("db/migrate")
  end
end

私の場合、configureはwebプロセス本体に入れました。

5. configureを記述します。
webプロセスのファイルの先頭(requireの後)に以下を追加します。

configure do
  config = YAML::load(File.open('config/database.yml'))
  environment = Sinatra::Application.environment.to_s
  ActiveRecord::Base.logger = Logger.new(STDOUT)
  ActiveRecord::Base.establish_connection(config[environment])
  Delayed::Worker.guess_backend
end

最後の行はDelayed::Workerの初期設定です。最小限、.guess_backendは入れてください。これでDelayed::Jobが動的に定義されます。


6. データベースのマイグレーションを実行します。

rake db:migrate

これで出来上がりです。

アプリケーションを実行する

必要なコーディングが終わったらアプリケーションを実行します。
webプロセスを実行する前にworkerプロセスを立ち上げる必要があるので、以下のようにします。

rake jobs:work
rackup


大勢の方がトライしてノウハウを書かれていますが、断片的で苦労しました。私の備忘録も断片的ですね…