Yesodが作ってくれるテンプレートプロジェクトでは、セッション情報をファイルに格納するようになっている。
しかしロードバランサ環境ではこれでは困るので、DBに格納するようにしたい。
Yesodでのセッションの実装を差し替える方法は存在していて、本エントリではその方法を紹介する。
2つのモジュール
次の2つのモジュールがキモ。
(リンク先はGitHubにしてあります)
使い方が書いてあるドキュメントがなかなか見つからなかったので結局ソースのコメントを見て探った。
2016.3.31追記
この辺りのモジュールの構成の意味を解説しているQiitaの記事がありました。ありがたいです。
ソースの修正
cabalファイル
cabalのbuild-dependsに次を追記。
, serversession
, serversession-frontend-yesod
, serversession-backend-persistent
スキーマをMigrateする処理を変える
セッション情報をDBに格納するにはスキーマのMigrate処理でテーブルを作る必要がある(蛇足だが、MongoDBの場合は不要な処理だと思う)。
まずModel.hsを修正。
修正前)
share [mkPersist sqlSettings, mkMigrate "migrateAll"]
$(persistFileWith lowerCaseSettings "config/models")
修正後)
share [mkPersist sqlSettings, mkSave "entityDefs"]
$(persistFileWith lowerCaseSettings "config/models")
mkMigrate
関数を後で呼び出すので、ここではmodelsファイルのパース結果をentityDefs
に束縛するようにする(mkMigrateは2回呼び出すとエラーになるので)。
なおimportのmkMigrate
をmkSave
に変更するのを忘れずに。
次にApplication.hsに、セッション情報格納用のスキーマを定義する処理を追記する。
import qualified Data.Proxy as P
import qualified Web.ServerSession.Core as SS
import qualified Web.ServerSession.Backend.Persistent as SS
-- Create migration function using both our entities and
-- serversession-backend-persistent ones.
mkMigrate "migrateAll" (SS.serverSessionDefs (P.Proxy :: P.Proxy SS.SessionMap) ++ entityDefs)
ここでやっていることは、予めパースしておいたconfig/models
の結果とセッション情報を格納するスキーマ情報を結合した上でMigrateする、という処理。
sessionBackendの実装を差し替える
ストレージにセッションを格納するようにFoundation.hsを修正する。
まずはimportを追加。
import Web.ServerSession.Backend.Persistent
import Web.ServerSession.Frontend.Yesod
Yesodクラスのインスタンスにする際のmakeSessionBackend
関数の実装を変更する。
-- | Cookie name used for the sessions of this example app.
sessionCookieName :: Text
sessionCookieName = "SESSION"
makeSessionBackend = simpleBackend opts . SqlStorage . appConnPool
where opts = setIdleTimeout (Just $ 5 * 60) -- 5 minutes
. setAbsoluteTimeout (Just $ 20 * 60) -- 20 minutes
. setCookieName sessionCookieName
セッションタイムアウトの数値は適当に変更してください。
課題
セッション情報を格納するDBとアプリケーション情報を格納するDBを分けたい、という要件があると思うので、これに対処する方法を今後検討したい。