Azure Function で Timerトリガーを試してみた(Windows10、Python)
Azure Function で Python の自作ライブラリを使うのと、Timerトリガーをローカルサーバーで動かすのに苦労したのでまとめます。
コードはこちら
Windows10、Pythonを前提としています。
デプロイについては書きませんが、環境設定含め下記サイトがとても詳しいです。
以下はメモ書き程度に備忘録として記載します。
環境設定
VS Code の使用を前提としているようです。
Azure Functions Core Tools に必要な Node.js をインストールし、VS Code に Azure Function の拡張機能をインストールします。
npm で コマンドラインで Azure Functions Core Tools V3 をインストールします。
npm install --global azure-functions-core-tools@3 --unsafe-perm true --save-dev
これにより コマンドラインで func コマンドが使えるようになります。
なお、func コマンドが認識されない場合は、環境変数 Path で 下記 npm フォルダを設定してみましょう。
C:\Users\ユーザーネーム\AppData\Roaming\npm
func コマンドの詳細については下記参照。
実行ファイルの作成
コマンドでPython用のAzureFunctionのプロジェクトを作成します。
必要ファイルが自動で作成されます。
なお、VSCode の Azure タブから GUI操作で作成しても同じです。
func init 任意のプロジェクトフォルダ --python
プロジェクトフォルダに移動します。
cd 任意のプロジェクトフォルダ名
venv で仮想環境を作成します。
python -m venv .venv
.venv\scripts\activate
以降で出てくる Function をローカルで実行する func start は仮想環境下で実行する必要があるようです。
このコマンドは仮想環境で実行する必要があります。
必要に応じて pipのアップグレードと requirement.txt からライブラリのインストールをするとよいでしょう。
python -m pip install --upgrade pip
pip install -r requirements.txt
ローカルで実行する Function 作成を作成します。
HTTPトリガーの場合は temlate 名を指定して作成できるようです。
func new --name ファンクションのフォルダ名 --template "HTTP trigger"
コマンドライン上で一覧から選択してトリガーを選択することも可能です。
func new --name ファンクションのフォルダ名
下記の func コマンドで作成可能な template のリストを出力することもできます。
func template list
Timer トリガーをローカルで実行すると、下記のエラーが出ました。
The listener for function 'Functions.HelloTimer' was unable to start. Azure.Core: Retry failed after 6 tries. Retry settings can be adjusted in ClientOptions.Retry.
Azure のエミュレーターが機能してないのが原因のようです。
Azurite を使うとエミュレーターの構築が便利でした。
Azurite を使うには、 npm で Azurite をインストールしてやります。
npm install -g azurite
C: 直下に azurite というフォルダを作成し、VS Code とは別のコマンドラインで下記コマンドを入力します。
azurite --silent --location c:\azurite --debug c:\azurite\debug.log
下記ログが出力され、Azure のエミュレーターが起動されます。
Azurite Blob service is starting at http://127.0.0.1:10000
Azurite Blob service is successfully listening at http://127.0.0.1:10000
Azurite Queue service is starting at http://127.0.0.1:10001
Azurite Queue service is successfully listening at http://127.0.0.1:10001
Azurite Table service is starting at http://127.0.0.1:10002
Azurite Table service is successfully listening at http://127.0.0.1:10002
VS Code のコマンドラインからTimerトリガーを実行します。
func start
すると、init.py ファイルのコメントを追記した部分が実行されます。
def main(mytimer: func.TimerRequest) -> None:
utc_timestamp = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc).isoformat()
if mytimer.past_due:
logging.info('The timer is past due!') ## ココが初期実行
logging.info('Python timer trigger function ran at %s', utc_timestamp) ## ココが定期実行
ログは以下のとおり。
[2021-10-24T10:28:47.349Z] Worker process started and initialized.
[2021-10-24T10:28:47.461Z] The timer is past due!
[2021-10-24T10:28:47.464Z] Python timer trigger function ran at 2021-10-24T10:28:47.459041+00:00
[2021-10-24T10:28:47.481Z] Executed 'Functions.HelloTimer' (Succeeded, Id=8e31eaf8-7ad7-49df-a756-bae82aa01543, Duration=396ms)
[2021-10-24T10:28:51.970Z] Host lock lease acquired by instance ID '00000000000000000000000088A4879D'.
Timerトリガーの実行時間を変更するには、function.json 内の schedule を修整すればよいです。
"schedule": "0 */1 * * * *"
それぞれの数字は下記の意味を表します。
{second} {minute} {hour} {day} {month} {day-of-week}
また、下記の記述を使って条件を設定することが可能です。
Type | 例 | トリガーのタイミング |
---|---|---|
特定の値 | 0 5 * * * * | 1時間ごとに1回、1日の毎時5分 |
すべての値 (*) | 0 * 5 * * * | 5時から始まる1時間で1分ごと |
範囲 (-演算子) | 5-7 * * * * * | 1分間に3回-各日、各時間、毎分5秒から7秒 |
値のセット (,演算子) | 5,8,10 * * * * * | 1分間に3回-各日、各時間、毎分5秒、8秒、10秒 |
間隔値 (/演算子) | 0 */5 * * * * | 1時間に12回-各日、毎時5分0秒 |
自作ライブラリの使用
プロジェクトフォルダ直下に自作ライブラリを格納するフォルダを作成し、その中に 実行したい.pyファイルと、空の init.py ファイルを格納すれば、Functionフォルダ内の init.py ファイルで自作ライブラリを import してトリガー実行することができます。
|----- .venv/
|----- .vscode/
|----- functionフォルダ(HelloTimer)/
| |----- __init__.py # 実行ファイル
| |----- function.json # トリガー情報(実行時間)が記載されたファイル
|
|----- 自作ライブラリを格納するフォルダ/
| |----- __init__.py # 中身は空っぽで問題ない
| |----- 自作ライブラリの.pyファイル(display_time.py)
|
|----- .gitignore
|----- getting_started.md
|----- host.json
|----- local.settings.json
|----- requirements.txt
試しに現在時刻を出力するだけの簡単な自作ライブラリを実行してみます。
import datetime
class display_time_now:
def time_now(self):
time = datetime.datetime.now()
return time
import datetime
import logging
import azure.functions as func
from display_time import display_time # 追加した自作ライブラリ
nowtime = display_time.display_time_now() # 追加
time = nowtime.time_now() # 追加
time_str = time.strftime('%Y/%m/%d %H:%M:%S') # 追加
def main(mytimer: func.TimerRequest) -> None:
utc_timestamp = datetime.datetime.utcnow().replace(
tzinfo=datetime.timezone.utc).isoformat()
if mytimer.past_due:
logging.info('The timer is past due!')
logging.info('Python timer trigger function ran at %s', utc_timestamp)
print(f"現在時刻 {time_str}") # 追加
以下のようにログが出力されます。
[2021-10-24T11:07:00.028Z] Python timer trigger function ran at 2021-10-24T11:07:00.027065+00:00
[2021-10-24T11:07:00.028Z] 現在時刻 2021/10/24 20:05:29
以上になります、最後までお読みいただきありがとうございました。
Discussion