最近、新しくデプロイした Azure Functions の TimerTrigger が何故か発火してくれない現象に悩んでいました。実際に Monitor で実行ログを確認すると、時間がめちゃくちゃになっています。
Consumption の場合は App Service Plan とは違う仕組みで動いているので、安定するのに時間がかかるのかとかタイムゾーンの設定を疑ったりしていましたが、結論から言うと違いました。
Azure Functions の TimerTrigger の精度低すぎでは pic.twitter.com/Bfyd0NsQ4I
— しばやん (@shibayan) 2018年9月28日
TimerTrigger の挙動が謎 pic.twitter.com/2mvQSeuaGB
— しばやん (@shibayan) 2018年10月1日
今は TimerTrigger を Let's Encrypt の証明書更新で使っているので、上手く動かない場合は割と致命的です。
いい加減になんとかせねばと真面目に調べたら、以下の Issue が引っ掛かりました。
どうやら Run From Package を使って外部 URL から zip をデプロイした場合に、正しく各 Trigger のメタデータが Scale Controller に同期されない問題があるらしいです。
コメントに書かれていた Workaround は以下になります。
- 明示的に Azure Portal から Restart を行う
- syncfunctiontriggers を実行する
Web Deploy を使っても解決するみたいですが、今更 Web Deploy には戻れません。修正が行われるまではどちらかの方法を実行する必要がありそうです。
手っ取り早いのは Restart ですが syncfunctiontriggers
の方は Azure Functions のアーキテクチャ部分を垣間見ることが出来るので、調べておいて損はない感じです。
最近は API ドキュメントからすぐに試すことが出来るので便利です。
ちなみに Azure Resource Explorer から実行することも出来ます。実行には多少時間がかかります。
そして Cloud Shell などから Azure CLI を使っても実行することが出来ます。ARM Action として提供されているので、割と簡単に叩くことが出来て便利ですね。
az resource invoke-action --resource-group <ResourceGroupName> --action syncfunctiontriggers --name <SiteName> --resource-type Microsoft.Web/sites
そもそも何故メタデータの同期が必要かというと、Queue や Timer の場合は実行しないといけないタイミングになっても、Function 本体がそもそも立ち上がっていないことがあるからです。
Consumption では必要な時に必要な数立ち上げることになるので、インスタンスを管理する Scale Controller はそういった Trigger の情報を知っておく必要があるというわけです。
今回、私の場合は TimerTrigger で発生しましたが、原理上は HttpTrigger 以外でも発生するので Run From Package を使って外部 URL の zip デプロイする際には気を付けましょう。
後から CRON 式を変更したり、新しく Function を追加した場合にもメタデータが同期されないことがあるみたいなので、地味にはまります。早く直ってくれると良いのですが、少し時間がかかりそうです。
うむ、直った pic.twitter.com/7l2gbBqpVH
— しばやん (@shibayan) 2018年10月1日
ちなみに syncfunctiontriggers
を実行後は TimerTrigger が正しく動くことを確認しました。