Durable Functions でたまに instanceId を取得したいときがあります。例えば Activity function で external Event の URL を作りたいときとか。私的にはあまり使わない Durable functions の Python ではどうだっけって気になったので、C# と Typescript も一緒にメモしておきます。
C#
まずは C# からです。
C# > Starter
以下のコードは Http の Starter のテンプレートのコードです。ここでは instanceId を自動生成させるか自分で作るかってところになります。
StartNewAsync
メソッドの第二引数でパラメーターをセットしない場合は、instanceId が自動生成されます。StartNewAsync
メソッドの第二引数でパラメーターをセットした場合は、それが instanceId となります。外部で instanceId を生成してここでも使いたいときは使える感じです。
[FunctionName("Function1_HttpStart")] public static async Task<HttpResponseMessage> HttpStart( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req, [DurableClient] IDurableOrchestrationClient starter, ILogger log) { var instanceId = await starter.StartNewAsync("Function1"); // 第二引数にセットするとその値が instanceId となる。 // var instanceId = await starter.StartNewAsync("Function1", "なんらかの ID"); log.LogInformation($"Started orchestration with ID = '{instanceId}'."); return starter.CreateCheckStatusResponse(req, instanceId); }
C# > Orchestrator
Orchestrator は IDurableOrchestrationContext
のプロパティから取得が可能です。
public static async Task<List<string>> RunOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context) { var instanceId = context.InstanceId; // 以下省略
C# > Activity
以下はテンプレートからコードを生成した際の Activiy trigger のコードです。[ActivityTrigger]
の直後に適当な型を定義することで、Orchestrator からのパラメーターを受け取ることができるコードになっています。
[FunctionName(nameof(SayHello))] public static string SayHello([ActivityTrigger] string name, ILogger log) { log.LogInformation($"Saying hello to {name}."); return $"Hello {name}!"; }
これをちょっと変えていきます。
InstanceId
は IDurableActivityContext
が管理しているので、以下のようコードを変更することで IDurableActivityContext
を受け取ることができます。そうすると Orchestrator からの渡されたパラメーターは context.GetInput<>()
で取得するようになります。
InstanceId
の取得とは全く無関係ですが、DurableClient
のバインド方法も書きました。ブログ冒頭で instanceId を使うのが「external Event の URL を生成したいとき」って書いたのですが、それには DurableClient
を使うのでついでに書きました。
[FunctionName(nameof(SayHello2))] public static string SayHello2( [ActivityTrigger] IDurableActivityContext context, [DurableClient] IDurableOrchestrationClient orchestrationClient, ILogger log) { var instanceId = context.InstanceId; var name = context.GetInput<string>(); return $"Hello {name}-{instanceId}!"; }
Javascript (Typescript)
TS > Starter
以下のコードは Http の Starter のテンプレートのコードです。ここでは instanceId を自動生成させるか自分で作るかってところになります。
startNew
メソッドの第二引数でパラメーターをセットしない場合は、instanceId が自動生成されます。startNew
メソッドの第二引数でパラメーターをセットした場合は、それが instanceId となります。外部で instanceId を生成してここでも使いたいときは使える感じです。
const httpStart: AzureFunction = async function (context: Context, req: HttpRequest): Promise<any> { const client = df.getClient(context); const instanceId = await client.startNew(req.params.functionName, undefined, req.body); context.log(`Started orchestration with ID = '${instanceId}'.`); return client.createCheckStatusResponse(context.bindingData.req, instanceId); }; export default httpStart;
C# とほぼ同じこと書きましたね...
TS > Orchestrator
以下のコードは orchestrator function のテンプレートのコードです。
instanceId は context
の中でいくつか存在していますが、context.bindingData.instanceId
でとるのがよいかなと。理由は Activity Function の context
と一緒の方法で取得できるのでってだけですが。
const orchestrator = df.orchestrator(function* (context) { // instanceId の取得 context.log(`instanceId (orchestrator): ${context.bindingData.instanceId}`); context.log(`Orchestrator: instanceId: ${context.bindingData.instanceId}`) context.log(`Orchestrator: instanceId: ${context.bindings.context.instanceId}`) context.log(`Orchestrator: instanceId: ${context.bindingData.context.instanceId}`) return "Hello"; }); export default orchestrator;
TS > Activity
以下のコードは Activity function のテンプレートのコードです。
instanceId は context.bindingData.instanceId
で取得できます。
const activityFunction: AzureFunction = async function (context: Context): Promise<string> { const instanceId = context.bindingData.instanceId; return instanceId ; }; export default activityFunction;
ちなみに Typescript で durableClient
を使うには、orchestrationClient or DurableClient を bind して df.getClient(instanceId)
みたいな感じでやります (面倒でここではかかなかった...)。
Python
py > Starter
starter での instanceId の話は基本的に他の言語と一緒なので内容が冗長なので省略します。
py > Orchestrator
Orchestrator では他の言語同様 context から取得します。変数名は instance_id
です。
def orchestrator_function(context: df.DurableOrchestrationContext): logging.info(f"instanceId: {context.instance_id}")
py > Activity
Node 同様に Python でもどうにかできるかと思いましたが、シンプルに関数の引数で instanceId 渡すのがよいのかなという結果に。
import azure.durable_functions as df
して試行錯誤しようとおもったけど、いい感じに出来そうにないので諦めました。
まとめ
Activity や Orchestrator へパラメーターとして渡せば楽に解決するのでそれでも悪くないのですが、無理やりじゃないお作法でのやりかたをメモしておきましたが、Python の Activity function はチーンでした。
そんなことはさておき Durable Functions 便利なので使いどころもたくさんですが、なんとなく概要がわかったから実装してみようって段階になったら、まずこのドキュメント読みましょう...っていう本題と関係ないオチで今回は締めくくります。