3

I recently upgraded to the isolated NET7 Azure Functions worker. Durable Function's API has changed quiete a bit in with that, but it is GA now.

I need to get the orchestration's instance id from within the activity function. Previously (with the in-process model), I was able to inject the IDurableActivityContext interface in the function and reference the instance id from there.

Afaik, the equivalent now is the TaskActivityContext class. However, if I inject this into the function it is always null.

How to get it? I could just pass it as an input from the orchestrator. But I would not prefer this.

namespace MyNamespace;

public class TestActionable
{
    private readonly ILogger _log;
    public TestActionable(ILogger<TestActionable> log) => _log = log;

    [Function("TestActionable_Trigger")]
    public async Task TriggerWorkflow([DurableClient] DurableTaskClient client,
    [QueueTrigger(QueueNames.ACTIONABLE_TEST, Connection = BindingConnectionNames.MY_BINDINGNAME)]string q)
    {
        var now = DateTimeOffset.UtcNow.ToIsoString();
        _log.LogWarning("Triggering workflow now");
        await client.ScheduleNewOrchestrationInstanceAsync("TestActionable_Workflow", input: now);
        _log.LogWarning("Triggered");
    }


    [Function("TestActionable_Workflow")]
    public static async Task RunWorkflow([OrchestrationTrigger] TaskOrchestrationContext ctx)
    {
        var log = ctx.CreateReplaySafeLogger("TestActionable_Workflow");
        log.LogWarning("Workflow started with input= {input}", ctx.GetInput<string>());

        var input = new { a=1337 };
        var output = await ctx.CallActivityAsync<bool>("TestActionable_Activity", input);
        log.LogWarning("Activity completed successfully= {output}", output);
        log.LogWarning("Workflow complete");
    }
    

    [Function("TestActionable_Activity")]
    public async Task<bool> RunActivity([ActivityTrigger] object input, TaskActivityContext ctx)
    {
        _log.LogWarning("Started activity, input= {i}", input);

        if (ctx is null)
        {
            _log.LogError("TaskActivityContext is null");
            return false;
        }

        _log.LogWarning("TaskActivityContext= {ctx}", ctx.Serialize());
        _log.LogWarning("The orchestration's instance id is= {ctx}", ctx.InstanceId);
        _log.LogWarning("Waited 1s, activity complete");
        await Task.Delay(1000);
        return true;
    }
}

Here's the log output

[2023-03-03T08:03:01.668Z] Executing 'Functions.TestActionable_Trigger' (Reason='New queue message detected on 'actionable-test'.', Id=1cc9891b-85a4-4dd4-90e2-19417cc7519a)
[2023-03-03T08:03:01.674Z] Trigger Details: MessageId: ae725935-4b5c-4299-ac48-44f1af934363, DequeueCount: 1, InsertedOn: 2023-03-03T08:03:00.000+00:00
[2023-03-03T08:03:01.863Z] Host lock lease acquired by instance ID '00000000000000000000000041F3D3B5'.
[2023-03-03T08:03:02.192Z] Scheduling new TestActionable_Workflow orchestration with instance ID '388c8c6c4f554f49ac1d9f50ac747e9b' and 28 bytes of input data.
[2023-03-03T08:03:02.192Z] Triggering workflow now
[2023-03-03T08:03:02.648Z] Triggered
[2023-03-03T08:03:02.757Z] Executed 'Functions.TestActionable_Trigger' (Succeeded, Id=1cc9891b-85a4-4dd4-90e2-19417cc7519a, Duration=1152ms)
[2023-03-03T08:03:06.020Z] Executing 'Functions.TestActionable_Workflow' (Reason='(null)', Id=0e4c510b-78c9-4e3a-8e9a-8f3cef8b4eb5)
[2023-03-03T08:03:06.213Z] Workflow started with input= 2023-03-03T08:03:02.12594Z
[2023-03-03T08:03:06.333Z] Executed 'Functions.TestActionable_Workflow' (Succeeded, Id=0e4c510b-78c9-4e3a-8e9a-8f3cef8b4eb5, Duration=358ms)
[2023-03-03T08:03:06.498Z] Executing 'Functions.TestActionable_Activity' (Reason='(null)', Id=07db96ca-df51-41e2-9906-e7012d7f2eda)
[2023-03-03T08:03:06.533Z] Started activity, input= {"a":1337}
[2023-03-03T08:03:06.533Z] TaskActivityContext is null
[2023-03-03T08:03:06.548Z] Executed 'Functions.TestActionable_Activity' (Succeeded, Id=07db96ca-df51-41e2-9906-e7012d7f2eda, Duration=56ms)
[2023-03-03T08:03:06.692Z] Executing 'Functions.TestActionable_Workflow' (Reason='(null)', Id=edde658a-c820-41bb-8d09-cc13ca14040d)
[2023-03-03T08:03:06.721Z] Activity completed successfully= False
[2023-03-03T08:03:06.721Z] Workflow complete
[2023-03-03T08:03:06.739Z] Executed 'Functions.TestActionable_Workflow' (Succeeded, Id=edde658a-c820-41bb-8d09-cc13ca14040d, Duration=52ms)

2 Answers 2

2

Apparently, this is by design. As noted here there is no equivalent in the isolated worker for DurableActivityContext. The TaskActivityContext I mentioned in my question, and which I figured to be the replacement for what I need (which it is not), appears to be only usable with the new approach of writing durable functions code, see class-based.

Sign up to request clarification or add additional context in comments.

Comments

2

To revive this, although there's no equivalent of IDurableActivityContext, there's still a way to get the instance ID of the orchestration. Add a string parameter to the activity function with the name "instanceId," and it will receive the instance ID.

If the activity function already has an input parameter, that one should be the one with the [ActivityTrigger] attribute. In that case, you don't need any attribute on the "instanceId" parameter.

5 Comments

[Function("foo")] public async Task Run([ActivityTrigger] string instanceId) returns an exception for me: Could not populate the value for 'instanceId' parameter. Consider updating the parameter with a default value
I could have sworn I'd tried it like that at the time and it worked, but trying it now, I get the same error. It does work for me though if instanceId is not the [ActivityTrigger]. So this works: [Function("foo")] public async Task Run([ActivityTrigger] string myArg, string instanceId)
Is this documented anywhere? @ChrisGillum
Now that you mention it, not that I know of. If I remember right, I found that out while looking at the source code for durable functions.
@briandunnington i just found this in the docs (learn.microsoft.com/en-us/azure/azure-functions/durable/…): metadata - .NET activity functions can bind to a string instanceId parameter to get the instance ID of the calling orchestration.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.