[Azure] Functions(V2)でTimer trigger --Python テンプレートのコードをステップ実行デバッグする方法

# 概要

定期的にDBの中身を掃除するという機能を実装するとき、Azure FunctionsのTimer triggerを使ってやろうということになりました。

デバッグ環境を作るのに少し手間取ったので次回以降スムーズにいけるように記録を取っておきたいと思います。

# 環境

```bash
❯ func --version
4.0.5530
```

vscode
![スクリーンショット 2024-04-04 051731.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3249097/56a7b804-72e2-b43b-00d5-c3e19b0c0c23.png)

vscode extensions
![スクリーンショット 2024-04-04 051841.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3249097/f081b593-e16d-eb84-d7e6-ae3e277992a7.png)
![スクリーンショット 2024-04-04 051813.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3249097/af0aea5c-093a-8234-7f83-40d25b3832cc.png)


# おおまかな流れ

1. functionsのローカルリソースを作る
1. vscodeで設定する


# functionsのローカルリソースを作る

```bash
$ func init func-time-trigger --python 
```

func-time-triggerに移動します。
```
$ cd func-time-trigger
```

下記のようなディレクトリ構造になっていると思います。

```bash
$ tree
.
├── function_app.py
├── host.json
├── local.settings.json
└── requirements.txt
```

次にそこで Timer triggerテンプレートのリソースを作成します。

```bash
$ func new --template "Timer trigger" 
```
すると下記の対話が始まりますが、一旦全部そのままで大丈夫だと思います。
```bash
$ func new --template "Timer trigger" 
Function Name: [timer_trigger]
Schedule: [0 */5 * * * *]
Appending to /home/tester/temp/func-time-trigger/function_app.py
The function "timer_trigger" was created successfully from the "Timer trigger" template.
```


# vscode で該当のディレクトリを開く

該当ディレクトリを開くと、vscodeが右下の方でAzure Functionsに最適化するかと聞いてきます。

![スクリーンショット 2024-04-04 053438.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3249097/dc6cb1e5-e00f-227f-8a52-2cbec8d58daf.png)

これをYesとすると、更にvscode上部でインタプリタを選ぶウィンドウが表示されます。

![スクリーンショット 2024-04-04 053538.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3249097/c490a879-4b34-5da0-44ba-5173b54cc91c.png)

これを選ぶと.venvディレクトリと加えて.vscodeディレクトリにjson群が生成されます。

![スクリーンショット 2024-04-04 053601.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3249097/f7869ffb-1ad8-ee9c-d700-b428b18e2bd6.png)

内容も一応記しておきます。

## json群の内容

```json:extensions.json
{
  "recommendations": [
    "ms-azuretools.vscode-azurefunctions",
    "ms-python.python"
  ]
}
```

```json:launch.json
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Attach to Python Functions",
      "type": "python",
      "request": "attach",
      "port": 9091,
      "preLaunchTask": "func: host start"
    }
  ]
}
```

```json:settings.json
{
    "azureFunctions.deploySubpath": ".",
    "azureFunctions.scmDoBuildDuringDeployment": true,
    "azureFunctions.pythonVenv": ".venv",
    "azureFunctions.projectLanguage": "Python",
    "azureFunctions.projectRuntime": "~4",
    "debug.internalConsoleOptions": "neverOpen",
    "azureFunctions.projectLanguageModel": 2
}
```

```json:tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "func",
      "label": "func: host start",
      "command": "host start",
      "problemMatcher": "$func-python-watch",
      "isBackground": true,
      "dependsOn": "pip install (functions)"
    },
    {
      "label": "pip install (functions)",
      "type": "shell",
      "osx": {
        "command": "${config:azureFunctions.pythonVenv}/bin/python -m pip install -r requirements.txt"
      },
      "windows": {
        "command": "${config:azureFunctions.pythonVenv}\\Scripts\\python -m pip install -r requirements.txt"
      },
      "linux": {
        "command": "${config:azureFunctions.pythonVenv}/bin/python -m pip install -r requirements.txt"
      },
      "problemMatcher": []
    }
  ]
}
```


# デバッグの開始

##  AzureWebJobsStorageの入力
デバッグを開始する前にlocal.settings.jsonのAzureWebJobsStorageの値を埋める必要があります。システムにエミュレーターがインストールされている場合、自分でなにかを記述しなくてもvscodeが勝手に入力してくれるみたいですが、私の場合それでは動かなかったので、Azureのストレージアカウントのアクセスキーの接続文字列を入力しました。

![スクリーンショット 2024-04-04 055209.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3249097/8f9f48e7-7a3d-cee2-b645-c4e126771423.png)


## ステップ実行の確認
ではいよいよ、コードのステップ実行をします。
通常、時間によって実行されるスクリプトですが、run_on_startup引数をTrueに設定することで、起動直後に一発timer_trigger()が実行されることになります。

```python:function_app.py
import azure.functions as func
import datetime
import json
import logging

app = func.FunctionApp()

@app.timer_trigger(schedule="0 */5 * * * *", arg_name="myTimer", run_on_startup=True,
              use_monitor=False) 
def timer_trigger(myTimer: func.TimerRequest) -> None:
    
    if myTimer.past_due:
        logging.info('The timer is past due!')

    logging.info('Python timer trigger function executed.')
```

この状態で、任意の場所にブレイクポイントを設定して、デバッグの開始ボタンを押します。

![スクリーンショット 2024-04-04 055004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3249097/f3d208fe-d608-a3ff-431e-1b1f11f6c48b.png)

その後ターミナルに起動ログが流れて

![スクリーンショット 2024-04-04 060043.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3249097/13f8e222-aa30-dbe6-56ac-b0ec58ec0f18.png)

ブレイクポイントの位置でコード実行が止まります。

![スクリーンショット 2024-04-04 060029.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3249097/832ab273-353f-d7cc-3a18-fd0813716e99.png)

以上です。