色んな事を書く

シンプルさを極めたエンジニアになりたい

Azure Function の timeout と Cancellation Token

Azure Function で Cencel Request が発生するとき

Azure Function の parameter には Cancellation Token を bind させることが出来ます。 これを渡すことで Host OS はアプリケーションコードに対して終了通知を送ることが出来ます。 受け取ったアプリケーションコードは終了通知をもとに安全に処理を終える事が出来ます。

learn.microsoft.com

Parameter に渡した Cancellation Token から Cancel request が飛んでくるタイミングは以下があります。

  1. Deploy に伴うシャットダウン
  2. 明示的な再起動やチャットダウン
  3. スケールダウン
  4. Azure Function の Timeout

他にもあると思う。でも全ては把握できていません。 4 番の Timeout 時の挙動について少し見ていきます。

Azure Function での Timeout

Azure Function は host.json に timeout の時間を指定できます。 プランによって色々異なるが割愛しておきます。

んで、timeout 時の挙動を見てみたいのでとりあえず 10 秒で timeout が発生するようにしてみます。

{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "functionTimeout": "00:00:10"
}

他にもいろんなプロパティをセット出来るので以下を参照してください。

learn.microsoft.com

んで、この状態で HttpTrigger の Azure Function を作ってみて、無理やり Timeout を発生させてみましょう。

public static class Function1
{
    [FunctionName("Function1")]
    public static async Task Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log,
        CancellationToken cancellationToken)
    {
        try
        {
            await Task.Delay(TimeSpan.FromSeconds(11));
        }
        catch (OperationCanceledException e)
        {
            Console.Write(cancellationToken.IsCancellationRequested);
            log.LogError(e, e.Message);
        }
    }
}

この Function を実行すると以下のような Error Log を出してアプリケーションを終了させています。

Timeout 発生時に何か処理を挟みたい時は OperationCanceledException を catch すればよいことが分かりました。 ただし、Cancel request を受け取ったあと実行する処理には時間的制限もあります。 しばやんさんの記事には 10 秒間の猶予があると書いてあります。 ただし、これは Azure Function v2 の事なので v3 以降は挙動が変わっているかもしれません。

blog.shibayan.jp

cancel request を受け取ってからの重たい処理をしてしまうと強制シャットダウンを食らいデータ不整合を起こしてしまうかもしれないので気を付けましょう。

Http Trigger での Cancellation

Http Trigger を使えば Http Request で起動する Azure Function を作ることが出来ます。 HTTP Method も一通り使えるので簡単な REST API を作ることが出来ますね。

Azure Function に渡した Cancellation token では client が接続を切った場合の cancel request を受け付ける事が出来ません。 そうするとコネクションは切られたのに Azure Function の実行は続きっぱなしという状態になってしまいます。 対策としては HttpContext.RequestAborted が使えるのですが、この Cancellation token を引き回すと Parameter に渡した Cancellation token を使う事が出来ません。

learn.microsoft.com

なので Cancellation token を Link させましょう。

public static class Function1
{
    [FunctionName("Function1")]
    public static async Task Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log,
        CancellationToken cancellationToken)
    {
        var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, req.HttpContext.RequestAborted);
        try
        {
            await SomHeavyProcess(linkedToken.Token);
        }
        catch (OperationCanceledException e)
        {
            Console.Write(cancellationToken.IsCancellationRequested);
            log.LogError(e, e.Message);
        }
    }
}

こうすることで

  • Host からの Cancel request
  • Http connection が切断されたときの Cancel requset

を受けるけることが出来ます。