こんにちは。半年前に買った車がぶっ壊れたりした石川です。無料で修理してもらいました。
車はどうでもいいんで今回は Azure Functions を使うときに覚えておきたいことの話です。
Functions 便利ですよね。便利が故になんでも Functions で処理させたくなります。
Timer Trigger を使ってバッチ処理とか、Http Trigger を使って軽い API とか、Queue Trigger を使って大量データの処理とか。
ともかくいろんな使い道があります。
とても便利なのですが、サーバーレス特有の "覚えておいた方がいいこと" というものがあるので紹介します。
Timer Triggerの起動時の挙動
Timer Trigger は時間をトリガーとして動き出すトリガーです。
例えば
- 朝 9 時に動き出す
とか
- 朝 10 時と夕方 17 時に動き出す
とか。
さっくり日時を起点に動き出すものを作るにはとても便利なのですが、以下の場合にはちょっとした注意が必要です。
- アプリをデプロイする
- 停止してある Functions を起動する
- 再起動する
Azure Functions は作成時に Storage Account が自動で作成され、そこで実行に必要なファイルを配置/保持します。
ちょっと見てみましょう。
Azure Functions は Timer Trigger があると Trigger ごとにファイルを生成し、そこで前回実行日時、次回実行日時、ファイルの最終更新日時を保持します。
見やすくしたものは↓のような感じ。
{
"Last": "2021-01-01T00:00:00.0000000+00:00(最終実行日時UTC)",
"Next": "2021-01-01T00:00:00.0000000+00:00(次回実行日時UTC)",
"LastUpdated": "2021-01-01T00:00:00.0000000+00:00(最終更新日時UTC)"
}
Timer Trigger は起動時にこのファイルがあればこの情報を使い、動き出します。また、起動時に関数の引数として渡される TimerInfo 型の変数にはこのファイルから読んだ情報が入っています。
もし仮に、起動時に Last
の時間を過ぎていた場合、当該の Functions が起動したタイミングで動き出すようになっています。
RunOnStartup
起動時に無条件で実行するかどうかを決める設定値です。
function.json
かコード内で定義します。開発中には便利な機能ですが true
でセットしたままデプロイすると起動時に動き始めます。
想定してない動きをしているときには真っ先に疑いましょう。
処理中の再起動
Azure Functions は FaaS サービスであるため、不定期に基盤の更新が行われます。
過去に遭遇したものだと、"基盤の更新により環境変数が変更され自動で再起動された" というものがあります。
環境変数の大文字スネークケースで定義されているものなど、 Azure で自動設定されるものは動作中に変更されることがあるようです。
これが起きてしまうと、もちろんですが実行中のものは全て強制終了扱いとなり、処理が行われません。
Http Trigger など数ms〜数秒程度で済む処理ではリトライ実装などを行えば問題ありませんが、Timer Trigger で1時間かかるようなものを動かしていた場合にはそうもいかないのでそういったことに使おうとしている場合には注意が必要です。
強制的な再起動 + Timer Triggerの前回実行チェックが働いて2回目が動き出した!なんてこともありえるので気をつけましょう。
(できるならデカい処理はもっと別のサービスを使うか細かく刻んであげましょう)
Timer Triggerの精度
Timer Trigger は基本的に指定した時間通り動きますが、偶発的に数ms〜1s程度の誤差が生じる場合があります。
これまた、過去に遭遇した事例なんですが、 "午前9時に実行するようにしていたら08:59:99.96xxxxに動き出し、想定外の挙動をした" といったことも起こり得ます。
時間基準で動くものをベタ書きするなって話でもありますが、遭遇してわかることもあるということで紹介させていただきました。
これの対策としては、
- 当該関数を Http Trigger に変更し、時間が担保できるものから HTTP 経由で呼び出しを行う
- トリガー時間を少しずらして設定する
1つ目は少し使用していて、実際に Http Trigger に変更し、Logic App の HTTP コネクタで呼び出す といったことをしています。
ちなみに、 Logic App の HTTP コネクタには2分のタイムアウトがあるため、バッチのようなデカい処理をこれでやろうとすると Logic App からは全て "失敗" 表示になります。さらに、HTTP コネクタにはデフォルトでリトライが設定されてますので4回くらい叩かれます。愉快ですね。
2つ目はあまりおすすめできないですね。これ。結局誤差起きますし。割と悪ノリで書いてます。
余談ですが、時間基準で動くものは、いい感じに HTTP のリクエストボディで動きを変えるように書き換えました。
Functions のタイムゾーン
Azure Functions のデフォルトのタイムゾーンは UTC(+00:00) となっています。
これはアプリが取得できる時間にも関わってきます。
例えば、以下のコードを日本時間の午前9時に実行したときに出力される値は 00:00:00 です。
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss"));
変更するには環境変数(Functionsブレード -> 構成)に WEBSITE_TIME_ZONE
という名前で Tokyo Standard Time
と設定してあげると良いです。
おわり
という感じで、 Functions を使ってきて遭遇したことの紹介みたいになってしまいましたが、覚えておくと嬉しいことの紹介でした。
それでは〜〜〜〜〜〜