こんにちは。青木です。
この投稿はF# Advent Calendar 2011の12/22エントリです。
←前回 @zecl F# Implementation of BackPropagation Neural Network for Pattern Recognition(LifeGame)
10月のイベントでMSとMVPの方にF#の良さを色々と教えてもらいました。
また、豆蔵の方から関数型言語の話を聞く機会が増えてきました。
そんなこともあり、関数型言語F#とMicrosoftのクラウドであるAzureを組み合わせたアプリケーション構築にチャレンジしてみました。
作成するアプリケーションの内容
作成するアプリケーションはWindows AzureのWorkerRoleです。WorkerRoleは、アプリケーションサーバー的な役割を果たします。
実装する処理は、AzureのQueueストレージにデータが存在すればメッセージを取り出し、その値をTableストレージに登録します。そして登録が終了すればQueueからメッセージを削除します。
それでは実装手順を見ていきましょう。
新しいプロジェクトの作成
まず、VisualStudio 2010を立ち上げ、新規のクラウドアプリケーションの作成を選択します。表示されたダイアログからF#のWorkerRoleを選択します。

OKを押すと、F#のWorkerRoleプロジェクトが作成されます。
生成されたプロジェクトとコード
次のようなプロジェクトが生成されます。

このままビルドすれば、開発環境で動作を確認することができます。
続けて、F#で処理を書いてみます。
OnStartメソッドに初期処理を追記
まず、OnStartメソッドに設定ファイル(ストレージ情報)を読み込むコードを記載します。
---------------------------------------------------------------
//設定ファイル用の処理
let envConfig configName (setter:Func<string, bool>) =
let configValue = RoleEnvironment.GetConfigurationSettingValue(configName)
setter.Invoke(configValue) |> ignore
let act = new Action<string, Func<string, bool>>(envConfig)
CloudStorageAccount.SetConfigurationSettingPublisher(act)
---------------------------------------------------------------
Entityクラスを定義
次にTableストレージで使うクラスを定義します。
F#は書いた順番に読みだされるので、WorkerRoleクラスの上にこのクラスを定義します。
本来は新しいF#ファイルを作ってソリューションエクスプローラでWorkerRoleファイルの上に持っていくべきですが、今回はてっとり早くWorkRoleクラスと同じファイルに記載しました。
---------------------------------------------------------------
// TableストレージのEntity用のクラス
type UserEntity() =
inherit TableServiceEntity()
do //コンストラクタで、親クラスのプロパティ呼び出し
base.PartitionKey <- DateTime.UtcNow.ToString("yyyyMMdd")
base.RowKey <- Guid.NewGuid().ToString()
//名前を保存するプロパティ
let mutable name = ""
member this.Name
with get () = name
and set (value) = name <- value
---------------------------------------------------------------
Runメソッドにメイン処理を追記
最後にメイン処理のRunメソッドに、ストレージの準備、Queueを読み出す処理、Tableに登録する処理を記載します。
---------------------------------------------------------------
// Runメソッド
override wr.Run() =
log "WorkerRole1のエントリポイントが呼ばれました" "Information"
// 設定ファイルの読み出し
let storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString")
// キュー
let queueStorage = storageAccount.CreateCloudQueueClient()
let queue = queueStorage.GetQueueReference("entry")
// テーブル
let tableStorage = storageAccount.CreateCloudTableClient()
tableStorage.CreateTableIfNotExist("users") |> ignore
let context = tableStorage.GetDataServiceContext()
// メイン処理
while(true) do
Thread.Sleep(10000)
log "動作しています" "Information"
// キューから取り出し
let msg = queue.GetMessage()
if msg <> null then
// キューにメッセージがあれば取り出して、テーブルに保存
let entity = UserEntity()
entity.Name <- msg.AsString
context.AddObject("users", entity)
context.SaveChanges() |> ignore
queue.DeleteMessage(msg);
log "1件処理しました" "Information"
else
log "データがありません" "Information"
---------------------------------------------------------------
実行
これらのコードを書いたら、ビルドして実行します。
なお、ストレージ情報をDataConnectionStringの設定に記載しておく必要があります。

Visual Studioでデバッグ実行すると、ストレージのエミュレーターが起動します。実行ログが出力されていることが分かります。

AzureStrageExploreでQueueに名前を入れたメッセージを登録すると、正しくTableにアイテムが登録されることがわかります。

最後に
今回は、C#で書くようなコードを、F#で書いてみました。
関数型言語に触れる目的でコーディングをしてみましたが、OOPに慣れているためか、手続き型で書いてしまいました。(正確には、いきなり関数型でコーディングしようとしても難しかったので、F#の構文を学ぶため、手続き型のC#のコード移植から踏み込んでみました。)
それでも、F#という言語には触れることができ、楽しく新しい刺激を受けることができました。
マルチサーバー・マルチコアで動作するWorkerRoleですので、今後は関数型言語のアプローチでプログラムを書いていきたいと思います。
サンプルコードのダウンロード(WokerRole.fs)
WorkerRole
↑今回紹介したサンプルコードは上記のリンクからダウンロードできます。ZIPで圧縮しています。