つばろぐ

主に C#, .NET, Azure の備忘録です。たまに日記。

backlackでBacklog Webhookのテストを行う方法

以前、Backlogの通知をSlackにも通知するためのツール「backlack」を作ったという記事を書きました。
backlackについてはこちらの記事をご覧ください。

tsubalog.hatenablog.com

github.com

BacklogにはWebhookのテスト送信を行う機能があります。
ですがbacklackを開発しているときには、このWebhookのテスト送信機能を使ったテストがうまく動作しませんでした。

www.backlog.jp

そのため実際にチケットを操作しながらテストを行っていましたが、うまく動作しなかった原因が分かりました。

まずAzure Functionsにデプロイした settings.js には、下記のように実在するBacklogプロジェクトのキーを登録している状態とします。(URLはダミーです)

// Replace {your-space} to your backlog space name.
exports.ticketUrl = 'https://mtmr.backlog.jp/view/{key}';
exports.ticketCommentUrl = 'https://mtmr.backlog.jp/view/{key}#comment-{id}';
exports.pullRequestUrl = 'https://mtmr.backlog.jp/git/{key}/{repo}/pullRequests/{number}#comment-{id}';
exports.channels = {
    TASK_1: 'https://hooks.slack.com/services/xxx/yyy/zzz',
};
exports.statuses = ['', '未対応', '処理中', '処理済み', '完了'];

この状態でWebhookのテスト送信を行うとエラーになります。エラーメッセージはこちらです。

2017-07-01T00:17:23.174 Function completed (Failure, Id=bb0c1402-4cb0-459c-947e-bb3f7a2ed502, Duration=7714ms)
2017-07-01T00:17:23.487 Exception while executing function: Functions.comment-notification. mscorlib: Error: options.uri is a required argument
    at Request.init (D:\home\site\wwwroot\comment-notification\node_modules\request\request.js:232:31)
    at new Request (D:\home\site\wwwroot\comment-notification\node_modules\request\request.js:128:8)
    at request (D:\home\site\wwwroot\comment-notification\node_modules\request\index.js:54:10)
    at Function.post (D:\home\site\wwwroot\comment-notification\node_modules\request\index.js:62:12)
    at module.exports (D:\home\site\wwwroot\comment-notification\index.js:165:21)
    at D:\Program Files (x86)\SiteExtensions\Functions\1.0.11015\bin\azurefunctions\functions.js:93:24.

完全に例外が出てますね。ではこのとき送信されたWebhookデータはこちらになります。

{
    "created": "2017-07-01T00:17:14Z",
    "project": {
        "archived": false,
        "projectKey": "TEST",
        "name": "TestProject",
        "chartEnabled": false,
        "id": 100,
        "subtaskingEnabled": false
    },
    "id": 10,
    "type": 17,
    "content": {
        "summary": "test issue",
        "key_id": 100,
        "description": "test description",
        "comment": {
            "id": 200,
            "content": "test comment"
        },
        "id": 100
    },
    "notifications": [],
    "createdUser": {
        "nulabAccount": {
            "nulabId": "XXX",
            "name": "yuta",
            "uniqueId": "yuta"
        },
        "name": "yuta",
        "mailAddress": null,
        "id": 67391,
        "roleType": 1,
        "userId": null
    }
}

project > projectKey に、settings.jsに定義されていないプロジェクトキーのデータとなっています。

ということで、どうやらBacklogのWebhookのテスト送信はTESTというプロジェクトキーが使われるようです。
なのでsettings.jsにテスト用のキーも定義してあげれば、Slackまで連携することができます。

f:id:tech-tsubaki:20170701095059j:plain

Azure Functionsの出力バインドにCosmos DBを指定してローカル開発を行う

Azure Functionsには関数の呼出し(トリガー)と、関数で処理したデータの出力先を定義する必要があります。
それらの入出力にAzureのサービスなどを紐付けることを「バインド」と表します。

docs.microsoft.com

Azure FunctionsでタイマーやAzure Storageなどがトリガーとしてサポートされています。
またバインドできる出力先には、Azure StorageやSQL Database、Cosmos DBやプッシュ通知などがあります。

今回は出力バインドにCosmos DB(DocumentDB)を指定した構成でのローカル開発環境に必要な設定を紹介します。
なおVisual Studio 2015を使った開発環境を前提としてます。

サンプルも作ってありますので、良かったら参考にしてみてください。

github.com

Azure Functionsのローカル開発環境の整備

ブチザッキに従いましょう。

Azure Functions のローカル開発 | ブチザッキ

Cosmos DBのエミュレータのインストー

こちらの記事冒頭の「Binaries > Download MSI」のリンクをクリックして、インストーラを入手しましょう。
手っ取り早いのはインストール式のエミュレータですが、Dockerイメージとしても提供されているようです。 docs.microsoft.com

Cosmos DB(当時はDocumentDB)のエミュレータについては2016年末に軽くブログで紹介しています。

tsubalog.hatenablog.com

Azure Functionsの出力バインドの設定

Visual Studioで関数を作成すると function.jsonというファイルが生成されます。
例えば単純なHTTPを入出力バインドとした構成はこちら。

{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "function",
      "name": "req",
      "type": "httpTrigger",
      "direction": "in"
    },
    {
      "name": "res",
      "type": "http",
      "direction": "out"
    }
  ]
}

次に出力バインドをCosmos DB(DocumentDB)用に変更します。

{
  "disabled": false,
  "bindings": [
    {
      "authLevel": "function",
      "name": "req",
      "type": "httpTrigger",
      "direction": "in"
    },
    {
      "name": "res",
      "type": "documentDB",
      "databaseName": "mlb",
      "collectionName": "players",
      "createIfNotExists": true,
      "connection": "documentDB",
      "direction": "out"
    }
  ]
}

注意点

connectionの値名称自体は任意に設定可能ですが、ここにDocumentDBの接続先情報がリンクされます。
では接続先情報をどこに定義するかというと、appsettings.jsonになります。
appsettings.jsonとはアプリケーション設定を定義するために使用されるファイルとなります。
Azure Functionsに限らず、Azure App Servicesのアプリケーションの開発でよく使用されるファイルですね。

このファイルに接続先情報を定義してもよいし、ローカル開発環境向けにappsettings.jsonを複製・リネームしたlocal.settings.jsonに定義しても良いです。
デバッグ実行時はlocal.setting.jsonが存在すれば、そのファイルを優先して参照してくれます。

appsettings.jsonもしくはlocal.settings.jsonに、DocumentDBの接続文字列を定義します。
Cosmos DBのエミュレータを接続先としたサンプルはこちらです。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "AzureWebJobsDashboard": "",
    "documentDB": "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
  }
}

function.json > "connection"に定義した名称と、appsettings.jsonもしくはlocal.settings.json > "Values"に定義した名称がリンクされるという仕組みになっています。

データをCosmos DBに出力するコード

次に関数のコードの変更になります。エントリポイントのメソッドの第2引数にout修飾子つきの引数を定義することで、その引数にセットされたデータが出力バインドに流し込まれるという仕組みです。C#のサンプルはこちらをご覧ください。

docs.microsoft.com

Cosmos DBエミュレータにデータを出力してみる

ここまでの設定が済んだらCosmos DBエミュレータを起動したうえでデバッグ実行を開始して、関数のエンドポイントをコールしてみましょう。
タスクバーにCosmos DBエミュレータのアイコンを右クリックし、「Open Data Explorer」をクリックするとデータを確認することができるページが表示されます。

f:id:tech-tsubaki:20170702151528j:plain

まとめ

ここまでAzureのサービスを使用したアプリケーションを作ってきましたが、一切Azure上にリソースを作成していません。
開発がローカルで終始するなんて凄くいいですよね。
今回のサンプルはAzure FunctionsでWebページのスクレイピングを行っているのでインターネットに繋がっている必要がありますが、処理によってはオフラインでデータ出力までの開発を行うことができますね。

Visual Studio Tools for Azure Functionsでデバッグできない現象を解決する方法

仕事や趣味でAzure Functionsのアプリケーションを作ることがちょくちょくあります。
サーバを作るほどでも無いちょっとしたアプリケーションをホストするにはとても使い勝手がよいです。

Visual Studio 2015を使えば、Azure Functionsのローカル開発を行うことができます。詳しくはこちらをご覧ください。

Azure Functions のローカル開発 | ブチザッキ

通常、デバッグを実行するとlocalhostのWebサーバが起動し、Functionsの関数へのエンドポイントが実行されます。
しかし、いつからかデバッグできない状態に陥っていました。(Visual Studio 2017をインストールしてからかも?)

具体的にはlocalhostのWebサーバは起動するが、関数のエンドポイントが繋がらず 503 Service Unavailable となってしまいます。

f:id:tech-tsubaki:20170701205119j:plain

Warning: The filename 'appsettings.json' is deprecated. Rename it to local.settings.json

                  %%%%%%
                 %%%%%%
            @   %%%%%%    @
          @@   %%%%%%      @@
       @@@    %%%%%%%%%%%    @@@
     @@      %%%%%%%%%%        @@
       @@         %%%%       @@
         @@      %%%       @@
           @@    %%      @@
                %%
                %

Listening on http://localhost:7071/
Hit CTRL-C to exit...
[2017/07/01 11:30:42] Reading host configuration file 'D:\Functions\host.json'
[2017/07/01 11:30:42] Host configuration file read:
[2017/07/01 11:30:42] {
[2017/07/01 11:30:42]
[2017/07/01 11:30:42] }
[2017/07/01 11:30:42] Loaded custom extension: BotFrameworkConfiguration from ''
[2017/07/01 11:30:42] Loaded custom extension: SendGridConfiguration from ''
[2017/07/01 11:30:46] Generating 1 job function(s)
[2017/07/01 11:30:46] Starting Host (HostId=matvaio-1730734029, Version=1.0.11002.0, ProcessId=9884, Debug=False, Attempt=0)
[2017/07/01 11:30:46] Found the following functions:
[2017/07/01 11:30:46] Host.Functions.Hoge
[2017/07/01 11:30:46]
[2017/07/01 11:30:46] Job host started
The host is taking longer than expected to start.
The host is taking longer than expected to start.
The host is taking longer than expected to start.

The host is taking longer than expected to start.という出力が延々続いて、何もできない状態となります。
Visual Studio 2015の修復や、Visual Studio Tools for Azure Functionsの修復を何度か試しましたが、改善されず放置していました。
まぁVisual Studio 2017に開発ツールが出てくるのを待てばいいや、というスタンスでした。

しかしやはり不便だったので解決方法を調べてみると、Azure Functions CLIリポジトリにIssueがあがっていました。

github.com

このIssueで述べられていた内容としては、デバッグ時に使用するポート(既定では7071)が既にシステムに登録されているよ、という内容でした。
コマンドプロンプトを管理者権限で起動し、次のコマンドを入力しましょう。

netsh http delete urlacl url=http://+:7071/

私もこのコマンドを使用することでデバッグできない問題が解消されました。
これでエンドポイントにアクセスすることができ、デバッグ実行を行うことができるようになりました。

f:id:tech-tsubaki:20170701205401j:plain

Azureの開発ツールもGitHubで管理・公開されるようになり、不具合に関する情報が見えやすくなってきていますね。
もし同じ現象で困っている方の参考になればいいなーと思います。