Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9314

Durable Functionsのファンアウト/ファンインパターンでのエラーハンドリング

$
0
0

Durable Functions は、サーバーレス コンピューティング環境でステートフル関数を記述できる Azure Functions の拡張機能です。(以下のURLからコピペした)
https://docs.microsoft.com/ja-jp/azure/azure-functions/durable/durable-functions-overview?tabs=csharp

チュートリアルに「ファンイン/ファンアウト」というパターンがある。

これのエラーハンドリングについて調べてみた。

1. 調べたかった事

オーケストレーター関数が複数のアクティビティ関数を呼び出したとする。

このとき、特定のアクティビティ関数だけエラーが発生したらどうなるのか?

そもそもエラーハンドリングできるのか?

エラーハンドリングをできたとして、エラーが発生したアクティビティ関数は特定できるのか?

エラーが発生した場合、成功した他のアクティビティ関数の結果はどうなるのか?使えるのか、使えないのか?

このあたりを知りたくて、簡単な関数を作成して、デバッグしてみた。

1. 作成した関数の概要

HTTPトリガーで起動するオーケストレーター関数と、オーケストレーター関数により起動するアクティビティ関数。

オーケストレーター関数はアクティビティ関数を10回並列で呼び出す。

アクティビティ関数は、引数のintをそのまま呼び出し元にリターンする。

ただし、アクティビティ関数は引数が4の倍数(0を除く)の時だけ例外をスローする。

オーケストレーターのソースは以下。(クリックするとソースが表示されます)
TaskOrch.cs
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Net.Http;usingSystem.Threading.Tasks;usingMicrosoft.Azure.WebJobs;usingMicrosoft.Azure.WebJobs.Extensions.DurableTask;usingMicrosoft.Azure.WebJobs.Extensions.Http;usingMicrosoft.Azure.WebJobs.Host;usingMicrosoft.Extensions.Logging;namespaceFunctionApp1{publicstaticclassTaskOrch{[FunctionName("Function2")]publicstaticasyncTask<int>RunOrchestrator([OrchestrationTrigger]IDurableOrchestrationContextcontext){vartasks=newTask<int>[10];varerrorMessageList=newList<string>();for(intindex=0;index<10;index++){// アクティビティ関数を並列で10回呼び出すtasks[index]=context.CallActivityAsync<int>("TaskActivity",index);}try{// 10個のタスクが終わるまで待つawaitTask.WhenAll(tasks);}catch{// エラーが発生したことをキャッチするConsole.WriteLine("Error has occured.");}// 成功の結果だけ集めてくるinttotal=tasks.Where(t=>t.Status==TaskStatus.RanToCompletion).Sum(t=>t.Result);// エラー結果だけを取得するvarerrors=tasks.Where(t=>t.Status==TaskStatus.Faulted).ToList();foreach(variteminerrors){Console.WriteLine(item.Exception.InnerException.InnerException.Message);}returntotal;}[FunctionName("Function2_HttpStart")]publicstaticasyncTask<HttpResponseMessage>HttpStart([HttpTrigger(AuthorizationLevel.Anonymous,"get","post")]HttpRequestMessagereq,[DurableClient]IDurableOrchestrationClientstarter,ILoggerlog){// Function input comes from the request content.stringinstanceId=awaitstarter.StartNewAsync("Function2",null);log.LogInformation($"Started orchestration with ID = '{instanceId}'.");returnstarter.CreateCheckStatusResponse(req,instanceId);}}}

アクティビティのソースは以下。(クリックするとソースが表示されます)
TaskActivity.cs
usingSystem;usingSystem.IO;usingSystem.Threading.Tasks;usingMicrosoft.AspNetCore.Mvc;usingMicrosoft.Azure.WebJobs;usingMicrosoft.Azure.WebJobs.Extensions.Http;usingMicrosoft.AspNetCore.Http;usingMicrosoft.Extensions.Logging;usingNewtonsoft.Json;usingMicrosoft.Azure.WebJobs.Extensions.DurableTask;namespaceFunctionApp1{publicstaticclassTaskActivity{[FunctionName("TaskActivity")]publicstaticasyncTask<int>Run(//[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,[ActivityTrigger]intnumber,ILoggerlog){log.LogInformation("TaskActivity start. index:"+number.ToString());log.LogInformation("Run datetime:"+DateTime.Now.ToString());awaitTask.Delay(1000);if((number%4==0)&&(number!=0)){// 0以外の4の倍数の時に例外をスローthrownewException("number:"+number.ToString()+" is a mulriple of 4.");}returnnumber;}}}

2. 結果

結論から言うと、成功した結果だけを取得できたし、エラーが発生したアクティビティを特定することもできた。

オーケストレーター関数が最終的に取得した結果は「33」。4の倍数だけカウントしてないから、1~9の和である45から12(=4+8)引いてるので結果も妥当。

例外はTask.WhenAllでキャッチする。というか、こうやってソースを見ると、Azure FunctionsというよりはTaskに関する知識な気がする・・・・

3. デバッグしてわかったこと

Exceptionの取り出し方にクセがある。

アクティビティ関数の例外で投げたメッセージを取得するために、innerExceptionを2回も使う羽目になるとは。。。。

4. 最後に

便利ですね、Azure Functions。

サーバーレスコンピューティングだし、エラーハンドリングどうなのかと思ってたけど、普通にできるんですね。

まあ、できるんだろうなー、程度には思ってたけど・・・・実際目で見ないとわからないからなぁ・・・・


Viewing all articles
Browse latest Browse all 9314

Latest Images

Trending Articles