Azure Serverless ワークショップ Deep Dive : モジュール 3

前回に続いて、今回はモジュール 3 の Deep Dive です。

GitHub: https://github.com/Azure-Samples/azure-serverless-workshop-team-assistant/tree/lang/jp/3-squirebot

概要

このモジュールではボットの本体を作ります。既存の GitHub 上のソリューションを使うため手順は簡単ですが、ここではコードを見ていきます。このソリューションにはボットの他に、タスク (コマンド) を登録するための Web アプリが含まれます。

プログラムの取得と実行

1. コマンドプロンプトより任意のディレクトで以下のコマンド実行。

git clone https://github.com/christopheranderson/squirebot

image_thumb[16]

2. まずボット側から。squirebot\src\task-functions に移動して code . コマンドで Visual Studio Code を起動。

image_thumb[18]

3. 次に package.json を確認。依存関係がすべて記述。Visual Studio Code の統合ターミナルより npm i を実行して依存関係をインストール。node_modules フォルダが作成されモジュールがコピーされる。

image_thumb[20]

4. 続いてコンソールより npm start を実行。4 つのファンクションが起動。フォルダ構成を確認し、function.json を含むフォルダがファンクション名となっていることを確認。

image_thumb[22]

image_thumb[24]

5. 既にモジュール 2 で出てきてた lanceFetcher から確認。function.json を開く。認証レベル、トリガーのタイプ、変数名等を含み、実際のスクリプトが index.js であることが scriptfile に記載あり。

image_thumb[26]

6. index.js も確認。module.exports で HttpRequest が来た際の処理だけ記述。C# と少しパターンが異なるため確認。Hello ファンクションも同様。Azure ファンクションは起動したまま次のステップへ。

7. 次に Web アプリ。新しいコマンドプロンプトで squirebot\src\webapp に移動して code . コマンドで Visual Studio Code を起動。

8. ターミナルより npm i を実行しパッケージの復元。

9. npm start で開始したら、URL を確認して、ブラウザでアクセス。画面が出たら正常。

image_thumb[85]

image_thumb[87]

bot ファンクション

bot ファンクションは Azure ファンクションとしての要素と BotFramework としての要素があります。

Azure ファンクション: bot\index.js

まず Azure ファンクションの実装を確認していきます。

1. module.exports で HttpRequest が来た際に要求を受ける処理を公開。LancerFetcher と異なり、listen(req, response(context)); の一行だけで実質内部関数を呼んでいるだけ。

image_thumb[28]

2. listen は const として定義されており、connector.listen が相当。

image_thumb[30]

3. connector は一番上に const として定義されており、../lib/bot を読み込んで、公開されている connector にアクセスしている。

image_thumb[38]

4. response 関数は listen の引数として渡している。この方法で既定の挙動を上書きできるが、ここではログを追加している程度であるためあまり気にしなくて良い。

Bot Framework モジュール lib\bot

次に Bot Framework のモジュールが格納されている lib\bot ディレクトリの中身を確認してきます。

1. ボットの本体は bot\index.js にある。また dialogs フォルダには 2 つのダイアログが存在。server.js は bot 単体で起動する際に利用する restfy を含んでいる、しかし今回は Azure ファンクションの一部として稼働し、ボット単体でホストしないため利用しない。

image_thumb[32]

2. bot 直下の index.js の実装を確認。冒頭から botbuilder の読み込みと、各ダイアログを取得、および connector と bot の作成。その後ダイアログのセットアップを行う。ここまではテンプレ通り。Bot Framework に触るのが初めての場合、こちらの記事の手順を一度やることを推奨。

image_thumb[34]

3. 一番下にある module.exports で connector を公開。これが Azure ファンクションの bot 関数から呼ばれているものの実体。

image_thumb[36]

Bot Framework ダイアログ

Bot Framework は 1 問 1 答の簡単なボットだけではなく、会話形式をサポートしており、その機能をダイアログと呼びます。詳細はこちら。このソリューションでは 2 つのダイアログがありますが、dialogs\index.js をメインに使い、handleParameters.js は子ダイアログとして実行されます。

1. メインのダイアログとなる dialogs\index.js を確認。冒頭でモジュールの読み込み。4 行目、5 行目ではタスク (コマンド) の一覧の読み込みや変更などを、ローカルのメモリから読み込むか、リモートのデータベースに対して行うかを、環境変数から取得。設定は local.settings.json にある。ワークショップの最後で CosmosDB を設定するが、その場合 UseInMemoryStore が false になる。7 行目ではタスクサービスをローカルから読み込むか、リモート Web API から実行するかを指定。その場合、合わせて TASKAPIHOST 名も正しく設定。

image_thumb[51]

2. Bot Framework のダイアログは、上から順番に処理されるウォーターフォール形式。まず一番初めの会話は挨拶確認。hello か squire を送られてきた場合は挨拶を返し、それ以外の場合は次の会話へユーザーからの入力を引数に遷移。

image_thumb[43]

3. 次の会話では、ユーザーから送られてきたメッセージ (コマンド) を検索。コマンドがあった場合、タスク (コマンド) に必要なパラメーターをユーザーに聞くために、handleParameters ダイアログを子ダイアログとして開始。タスク見つからない場合はエラーを返信。

image_thumb[45]

4. 最後の会話でマンドと、ユーザーから集めたパラメーターの値で、実際の処理を実行。

5. handleParameters.js を開くと、基本的には index.js と同じだが、必要なモジュールは botbuilder のみ。はじめの会話で index.js から受け取ったパラメーターの一覧を session オブジェクトに代入。確認するパラメーターがない場合は、そのまま endDialog を実行して index ダイアログに結果を返す。

image_thumb[47]

6. 次の会話で自分を再起呼び出し。全てのパラメーターがなくなるまで繰り返し。

image_thumb[49]

ボットの部分は以上で終わりです。ダイアログに慣れないと記述が複雑に見えますが、順番に見ると分かりやすいです。

タスクサービス

タスクサービス lib\tasks.js に実装があるタスク (コマンド) を扱うサービスで、タスクの CRUD (Create/Read/Update/Delete) を行う taskService と、タスクを実行する taskRunnerService があります

1. lib\tasks.js を確認。一番下で 2 つのサービスを公開。

image_thumb[53]

2. 15 行目から 56 行目で既定のタスクを定義。UseInMemoryStore が true の場合に初期のタスクとして利用されるため、はじめから ”Fetch me my lance” コマンド等が利用可能。コマンド実行 URL と必要なパラメーターが定義されている。Web アプリ起動時に 2 つタスクが出てきたのもこのため。

image_thumb[57]

3. その下で Action、Parameter、Task など各種モデルの定義。

image_thumb[61]

4. そこからタスクサービスの実装とモデルの定義。内容はタスクの CRUD。

5. さらにその下にタスクランナーサービスの実装とモデルの定義。基本的にはタスクにある URL やパラメーターを元に HTTP リクエストを送信、結果のハンドルを行う。

データベースサービス

タスクを格納する先を、メモリではなく MongoDB にするヘルパーが lib/mongohelper.js に実装されています。これはあくまでヘルパーなのでここでの解説はしません。

task-api ファンクション

Azure ファンクションとして公開されるサービスの 1 つで、タスクサービスをリモートサービスとして使う場合に利用されます。

1. task-api\index.js を確認。冒頭で ../lib/tasks を読み込んでいるので実体はタスクサービスを利用。

image_thumb[63]

2. ファンクションとしては 99 行目で run メソッドをだけを公開。run メソッドでは HTTP Verb 毎にタスクサービスの関数を呼び出す。

image_thumb[65]

ローカルのクラスを Web API として公開する参考としてとても勉強になります。

デバッグ

最後に Visual Studio Code でのデバッグ方法です。前回とほぼ同じです。

1. 今回の Azure ファンクションは npm start で起動しているが、start が実際に実行するコマンドは package.json に格納。ファイルを開き、scripts の start の引数をデバッグ用のものに変更。

func host start --debug vscode

image_thumb[79]

2. ターミナルより npm start で実行。変更した引数がついていることを確認。

image_thumb[83]

3. もしスクリプトを変更したくない場合は、npm start にダブルハイフンを付けると、それ以降を引数とできるため、同様の効果。

npm start -- --debug vscode

4. VSCode のデバッグメニューより F5 押下、または実行ボタンをクリック。ステータスバーがオレンジに変わればアタッチ完了。

image_thumb[67]

5. 必要な場所にブレークポイントを置いて実行。

ボットのデバッグ

折角なのでボットの部分をデバッグしてみましょう。

1. bot\index.js 40 行目にブレークポイントを設定。

image_thumb[69]

2. lib\bot\dialogs\index.js の 13 行目にもブレークポイントを設定。

image_thumb[71]

3. func host start で Azure ファンクションを開始。全てのファンクションが実行され、デバッガーが 5858 で待っていることを確認。

image_thumb[73]

4. Visual Studio Code でデバッグ開始。

5. BotFramework Emulator を開始し、http://localhost:7071/api/bot に接続。ID やパスワードは不要。

image_thumb[75]

6. Connect した瞬間にブレークポイントにヒットするので、F5 で継続。

7. hello と送信。再度ブレークポイントにヒット。F5 で継続。

image_thumb[77]

8. 続いてダイアログのブレークポイントにヒット。ここからは F11 等で好きにデバッグ。

Web アプリ

Angular 2 ベースの Web アプリです。このアプリを説明しだすと Angular 2 の世界にどっぷりですが、重要な点はワークショップでも触れている通り、タスクサービスのページと関連設定のみです。

Azure への展開

ワークショップでは開発したものを全て Azure に展開していますが、ここでも特に Deep Dive は必要なさそうなので割愛します。

まとめ

このモジュールでは Azure ファンクション、Bot Framework、CosmosDB、Angular と関連技術が山盛りのため、興味があれば勉強する材料には困りません。Serverless 観点からは Azure ファンクションだけ確認してください。次回はモジュール 4 を見ていきます。

中村 憲一郎