Azure プラットフォームのサービス正常性アラート通知について

Azure プラットフォームでは定期的にメンテナンスが行われ、問題が発生した場合も MS 側で対応が行われるので、利用している側が動く必要は、基本的にあまりない。 但し、例えば障害発生中は Azure 上で動かしているアプリにも影響が出ている可能性があるので、発生している問題の状況については把握しておき、必要に応じて対処する必要がある。

Azure プラットフォームで問題が発生した場合やメンテナンスが予定されている場合などは、Azure モニターのアラート機能を使用して状況の通知を受けることができるので、これを利用する。 基本的にサブスクリプションごとの通知設定が必要となるが、少なくとも、本番環境については通知を受けるようにしておき、状況を常に把握できるようにしておく必要がある。

通知設定手順

  1. 通知設定を行いたいサブスクリプションを Azure ポータルで開く
  2. 左のブレードから、[モニター] - [Service Health] - [正常性アラート] の順にクリックし、[サービス正常性アラートの作成] をクリックする

    f:id:poke_dev:20190803123246p:plain

  3. 「ルールの作成」画面が表示されたら、通知先 (アクション) の情報やルール名などを適宜設定し、ルールを作成する。この際「リージョン」設定については、基本的に全項目を選択しておいた方が無難と思われる (特定リージョンのみで全リソースが作成できることなどほとんどないため)

    f:id:poke_dev:20190803123316p:plain

  4. 当該サブスクリプションに影響する問題が発生した際などに、以下のようなメールが送信される

    f:id:poke_dev:20190806213702p:plain

参考

Actions on Google アプリへの Welcome Intent 定期アクセスについて

少し前から Actions on Google アプリに対して、8 分前後の間隔でヘルスチェック目的のクロールが行われるようになったようで、Dialogflow の History を見ると、GOOGLE_ASSISTANT_WELCOME の呼び出しが定期的に発生していることが確認できる。

Default Welcome Intent で Fulfillment を使っていなければ実害はないが、Webhook 呼び出しを行っている場合、この定期的なヘルスチェックで Webhook 側のリソースが消費されることになってしまう。

このヘルスチェックに対してコストをかけて処理するのは馬鹿らしいので、Webhook 側ではヘルスチェックによるリクエストかを判断して、ヘルスチェックに対しては可能な限りコストをかけずにレスポンスを返して処理を終わらせるのが良いかと思われる。

2019/8/1 現在、Webhook に渡される Json は以下のようになっている。「Crawler」とか「is_health_check」が判定に使えそうな感じ。

{
  "responseId": "xxxxx",
  "queryResult": {
    "queryText": "GOOGLE_ASSISTANT_WELCOME",
    "action": "input.welcome",
    "parameters": {
    },
    "allRequiredParamsPresent": true,
    "fulfillmentText": "知りたい仮想通貨を教えて下さい。",
    "fulfillmentMessages": [{
      "platform": "ACTIONS_ON_GOOGLE",
      "simpleResponses": {
        "simpleResponses": [{
          "textToSpeech": "知りたい仮想通貨を教えて下さい。"
        }]
      }
    }, {
      "platform": "ACTIONS_ON_GOOGLE",
      "suggestions": {
        "suggestions": [{
          "title": "BTC"
        }, {
          "title": "ETH"
        }, {
          "title": "LTC"
        }, {
          "title": "BCH"
        }, {
          "title": "XRP"
        }]
      }
    }, {
      "text": {
        "text": ["知りたい仮想通貨を教えて下さい。"]
      }
    }],
    "outputContexts": [{
      "name": "projects/xxxxx/agent/environments/__aog-4/users/-/sessions/xxxxx/contexts/actions_capability_audio_output"
    }, {
      "name": "projects/xxxxx/agent/environments/__aog-4/users/-/sessions/xxxxx/contexts/google_assistant_input_type_voice"
    }, {
      "name": "projects/xxxxx/agent/environments/__aog-4/users/-/sessions/xxxxx/contexts/google_assistant_welcome"
    }],
    "intent": {
      "name": "projects/xxxxx/agent/intents/xxxxx",
      "displayName": "Default Welcome Intent"
    },
    "intentDetectionConfidence": 1.0,
    "languageCode": "ja"
  },
  "originalDetectIntentRequest": {
    "source": "google",
    "version": "2",
    "payload": {
      "user": {
        "userId": "xxxxx",
        "profile": {
          "givenName": "Google",
          "familyName": "Crawler"
        },
        "locale": "ja-JP"
      },
      "conversation": {
        "conversationId": "xxxxx",
        "type": "NEW"
      },
      "inputs": [{
        "intent": "actions.intent.MAIN",
        "rawInputs": [{
          "inputType": "VOICE",
          "query": "仮想通貨チェック"
        }],
        "arguments": [{
          "name": "is_health_check",
          "boolValue": true,
          "textValue": "1"
        }]
      }],
      "surface": {
        "capabilities": [{
          "name": "actions.capability.AUDIO_OUTPUT"
        }]
      }
    }
  },
  "session": "projects/xxxxx/agent/environments/__aog-4/users/-/sessions/xxxxx"
}
参考

VS から Azure へ発行時、Could not find file エラーが発生する

Visual Studio から Azure 上の Functions リソースにプロジェクトを Web Deploy 発行する際、以下のようなエラーが発生することがある。

[出力] ウィンドウ

3>(2019/07/15 22:30:16) リモート コンピューターでの要求の処理中にエラーが発生しました。
3>Could not find file 'D:\home\site\wwwroot\App_Offline.htm'.

発行先 Azure Functions リソースのアプリ設定を確認し、WEBSITE_RUN_FROM_PACKAGE 設定の値が 1 で存在する場合は、値を 0 に変更するか、アプリ設定自体を削除する。

WEBSITE_RUN_FROM_PACKAGE が 1 の設定が存在する場合、アップロード先の Azure ストレージは読み取り専用扱いに変更されているため、当該ストレージに対して変更が行えず、本エラーが発生する。 前回 Zip 配置したリソースに対して Web Deploy しようとすると、本エラーが起きてしまう。

Azure Functions でしか確認していないが、恐らく Web Apps でも状況は同じと思われる。

azure web sites - What is going wrong with web deployment from Visual Studio and App service? - Stack Overflow

Azure Storage Emulator が起動できない時の対応

Azure Storage Emulator は Azure Functions のローカル実行時などに利用される。 起動できない場合の原因や対処方法は色々とあると思うが、自分が遭遇した問題についての対処方法。

Azure Storage Emulator の仕組み

Azure Storage Emulator は内部では MSSQLLocalDB を使用しているらしく、この DB が使えない状況だと Azure Storage Emulator が起動できない。

Azure Storage Emulator が起動していない状況だと、Azure Functions のタイマートリガーもローカルでデバッグ実行できない。

確認手順

  1. スタートから「Azure Storage Emulator」と入力して、「Microsoft Azure Storage Emulator」を起動する
  2. コマンドプロンプトが起動するので、以下のようにコマンド入力する

    AzureStorageEmulator init

  3. 以下のようなエラーが出る

    Cannot create database 'AzureStorageEmulatorDb57' : The database 'AzureStorageEmulatorDb57' does not exist.

  4. ユーザーフォルダのルート (%USERPROFILE%) をエクスプローラで確認する。上記名称のファイルが存在する場合、削除してから、AzureStorageEmulator の起動を試みてみる

遭遇しそうな状況: 自分の場合は、Windows 10 でユーザーファイルを残したままのリセットを行ったが、恐らくその時にリセット前の DB ファイルが残り、そのファイルをリセット後のユーザーでは使うことができずに、上記状況に陥っていたようだった。

参考

Outlook で送信トレイに入ったメールが送信されない時の対応方法

現象

  • メール送信しても、送信トレイに入ったまま送信されない
  • 送信トレイに入ったままのメールを開いて再度送信しても、送信トレイに残ったまま送信されない
  • 日付が「なし」に分類されている

対応方法

  • 「送信トレイ」から「下書き」フォルダにメールをドラッグして移動し、下書きフォルダ内で当該メールを開き、送信する

その他

  • 送信トレイで送信を 1 分遅延させるなどのクライアントルールを適用している場合、それが影響しているかも。その場合、一度無効にしてから新規メールを作成・送信して、結果を確認してみる

ThinkPad X1 Extreme の USB PD 充電について

ThinkPad X1 Extreme では USB Type-C を使った USB PD 充電が行えるが、保証はされていないようなので実際に充電できるのか確認してみた。

充電に使用したアダプタ

f:id:poke_dev:20190601201826j:plain:w350

結果

充電は問題なく出来る。充電速度は付属の AC アダプタとほぼ同じぐらいで、実用上特に問題ない速度。

以下は 1 分間の充電量

アダプタ PC 使用時(※) スリープ時
PD 約 1 % 約 1.3 %
付属 約 1 % 約 1.3 %

※ ブラウザやオフィスなど、低負荷状態での使用

大きさ、重さ
アダプタ 大きさ 重さ
PD 7.3 x 7.3 x 3 cm 約 275 g (付属ケーブル込み)
付属 11.5×7.5×2.2 cm 約 422 g (付属ケーブル込み)

f:id:poke_dev:20190601201853j:plain:w350

使用した USB PD 充電アダプタの補足
  • PC への充電と同時にスマホへの充電も可能だが、スマホへの充電を同時に行っても PC の充電速度の低下は特に見られなかった
  • 充電中の本体は、長くは持ちたくないぐらいには熱くなる
  • (USB ケーブルではない) コンセントを差し込む際、火花が散ることがあった (コンセント側で)
  • コンセント差込がケーブルタイプではなく本体直接タイプなので、付属アダプタのケーブルタイプと比べると、差込口を選ぶ
  • PC 接続時、「低速の USB 充電ケーブルが接続されています」と通知が出る、けど上述のように充電は出来るので、気にしないで OK

f:id:poke_dev:20190601202635p:plain

  • 自分は USB PD には詳しくないが、供給電力が足りないとそもそも充電できないらしいので、注意。上記で紹介しているアダプタは 87W 出力なので普通に充電できてるみたい。なお、PC 付属アダプタの出力は 135W

f:id:poke_dev:20190803112319p:plain

pc.watch.impress.co.jp

総評

ThinkPad X1E に普通に充電でき、USB Type-C であれば他のデバイスにも充電でき、且つ同時にスマホへも充電できるので、便利。 個人的には、サイズの面で厚みがやや気になった。後、コンセントの差込口も選ぶので、そこも注意。

厚みの件はあるが、充電対象を選ばないと言う点で、持ち運び時は付属のよりもこちらの方が役に立つと思います。

Azure Functions のタイマートリガーについて

  • 関数を指定したスケジュールに従って実行するトリガー (Timer trigger for Azure Functions | Microsoft Docs)

  • スケジュールは、CRON 式 (Azure Functions のタイマー トリガー | Microsoft Docs) で指定する。CRON 式の一番左のフィールドは分ではなく秒なので、注意

  • CRON 式は Run メソッドに直接定義することも出来るが、%ScheduleAppSetting% のようにアプリケーション設定の設定名で指定することもできる。直接定義すると、スケジュールを変更したい場合は Visual Studio で値変更した後、再度発行する必要があるが、アプリケーション設定であれば Azure ポータルから簡単に変更できるので、特に大きな理由がない限りはアプリケーション設定での設定を推奨

  • スケジュール実行間隔は、通常のスケジュール実行を行いたい場合は 1 分以上を推奨。1 分未満の間隔の場合、実行頻度の問題でランタイム側で UseMonitor が強制的に false にされる)

  • runOnStartup プロパティは、true に設定するとインスタンスの開始時に必ず対象タイマートリガーを実行する。インスタンス再起動時やスケールアウト時などが該当するが、通常のスケジュール実行が目的の場合は true にはしない事。既定値は false

  • useMonitor プロパティは、false に設定するとスケジュール実行状態をストレージに保存しない。インスタンス再起動時やスケールアウト時などに前回実行状態を判断できなくなるので、通常のスケジュール実行が目的の場合は false にはしない事。既定値は true

  • インスタンス起動時に、インスタンス停止中にロストしたスケジュール実行がなかったかチェックが行われる。ロストしたスケジュール実行が存在する場合、isPastDue プロパティを true に設定した上で、即当該メソッドの実行を行う。インスタンスが常に実行し続けていれば関係のない処理だが、例えば Azure のメンテナンス等によりスケジュール実行時間のタイミングでインスタンスの再起動が発生していた場合、この状態になる。なお、ローカルでのデバッグ時はほとんどインスタンス停止している状態のようなものなので、デバッグ開始時は isPastDue 状態となりやすい。isPastDue 状態での実行だから実行継続する、しないなどは単純には判断できないことが多いと思うので、ScheduleStatus の状態を確認し、本来の実行時間より 3 分以内の実行であれば isPastDue でも実行するなど、当該トリガーに合わせたカスタマイズが必要になると思われる

  • TimerInfo.ScheduleStatus のプロパティは以下の値が格納されている。Last と LastUpdated は同じなのでは?とか思うかもしれないが、スケジュール外の時間にタイマーが起動したなど必ずしもメソッド実行されているとは限らないので、そのような場合は LastUpdated だけ更新されることもあり得る

    • Last: 前回メソッド実行日時
    • Next: 前回 ScheduleStatus 更新した時点での、次のスケジュール実行予定日時
    • LastUpdated: 前回 ScheduleStatus 更新した日時
  • デプロイされたインスタンスが複数存在する場合も、実行されるのはそのうちの 1 つのインスタンスでのみ

  • 使用するストレージは、複数インスタンス存在時に 1 つのタイマーのみ実行する為の制御や、前回実行時のスタータス情報の保存等に使用する。host.json の id がストレージ使用時に利用されるので、複数の Function アプリで同じストレージ アカウントを共有しても、問題ない (異なる Function アプリで同じ id を明示的に設定しなければの話)

ストレージファイルのロック f:id:poke_dev:20190506153621p:plain

前回実行時のステータス情報 f:id:poke_dev:20190506153636p:plain

  • Functions v1 + 従量課金プランの組み合わせでの確認だが、複数の異なるタイマートリガーが同時に起動した際、そのうちの一つのタイマートリガー関数が処理終了したタイミングで、他の実行中のタイマートリガー関数が例外の発生もなしにいきなり処理終了 (Application Insights 上も失敗は記録されない) し、その後 isPastDue 付きで再起動する現象が発生することを確認している。

    これの一番の問題は、例外なしにいきなりプロセスが落ちること。例外ハンドルしての対応が行えず、Application Insights でのエラー観測も出来ない。

    複数インスタンスでの同時実行を防ぐためのストレージファイルロックが関係しているようだが、詳細な原因がちょっと不明なため、少なくとも Functions v1 + 従量課金プランの組み合わせでは、複数タイマートリガーの実行が重ならないようなスケジュール設定にするのが、無難。

    例えば HTTP トリガーのコールドスタート対策として定期間隔でタイマートリガーを使用している場合、それを別の Function アプリに外出しするなどが考えられる。

  • ランタイムのフローチャート GitHub - Azure/azure-webjobs-sdk-extensions: Azure WebJobs SDK Extensions

WebJobs.Extensions TimerListener.cs f:id:poke_dev:20190511160925p:plain

f:id:poke_dev:20190512211610p:plain

f:id:poke_dev:20190512213142p:plain

WebJobs.Extensions ScheduleMonitor.cs f:id:poke_dev:20190512212149p:plain