3

I have a scenario where I have 2 functions, let's say Function A and Function B.

Currently, Function A and Function B both have the same logic for logging failed activity where metadata is logged to Table Storage and JSON to Blob Storage.

Edit --> Function A and Function B are in two different Function Apps (intended). Function A is on a Consumption plan and Function B is on an App Service plan.

First question - would it make sense to create a Function C and take the failed activity logging logic from both A and B and put it in C?

This removes code duplication and the logic is in one place which is easier to manage.

Second question - what would be the best way to call Function C from A and B?

I have read here that it is best to use a Storage Queue or Service Bus for cross communication between Functions. The problem I have is - the JSON I need to store will in most cases exceed 256KB so I can't put it on a queue to trigger a Function.

So, could Function C be a HTTP trigger and I send a request containing all of my relevant information needed to log via HTTP from Function A and B?

Is there any reason not to do this?

Many thanks.

Chris
  • 3,113
  • 5
  • 24
  • 46
  • I think code duplication is the main problem you are trying to solve. Hope this article helps.. https://zimmergren.net/reuse-your-c-script-csx-code-in-multiple-azure-functions-2/ – Venkata Dorisala Aug 01 '17 at 15:21
  • @Venky thanks but Function A and Function B are in two different Function Apps (intended). Function A is on a Consumption plan and Function B is on an App Service plan. Sorry, I didn't mention, will edit my question. – Chris Aug 01 '17 at 15:26
  • The question is too broad/unclear/several questions in one – Mikhail Shilkov Aug 01 '17 at 15:48

2 Answers2

11

For future reference (and for those who may find this question via web searching), we've built a new Durable Functions extension to Azure Functions which allows calling one function from another. Your specific problem could potentially be coded up as follows:

public static async Task<object> Run(DurableOrchestrationContext ctx)
{
    try
    {
        var result = await ctx.CallActivityAsync<object>("FunctionA");
        var y = await ctx.CallActivityAsync<object>("FunctionB", result);
        return y;
    }
    catch (Exception e)
    {
        // error handling/compensation goes here
        await ctx.CallActivityAsync<object>("FunctionC", e);
        return null;
    }
}

FunctionA and FunctionB are activity functions that can live in the same function app. The function above which schedules them is an orchestrator function. Both Consumption and App Service plans are supported.

Under the covers the CallActivityAsync method sends a message via a Azure Storage queue to trigger the specified function by name. Large messages are supported by automatically switching to a combination of queues and blobs to ensure they can be delivered reliably.

One important constraint, however, is that FunctionA and FunctionB must be defined in the same function app. For that reason, it's not an exact match for your question. It's a great solution for those who can keep their functions in the same function app, however.

Official Documentation: https://learn.microsoft.com/en-us/azure/azure-functions/durable-functions-overview

GitHub: https://github.com/Azure/azure-functions-durable-extension

Chris Gillum
  • 14,526
  • 5
  • 48
  • 61
  • 1
    Durable Azure Functions need more love as they are super awesome :). I remembered reading about it a few days ago and thought of answering this question with that but unfortunately I was not able to find it (My Bing-foo/Google-foo failed me). I even looked on Azure App Service Blog but found no entries there regarding this. My suggestion would be to make this more discoverable. – Gaurav Mantri Aug 02 '17 at 06:33
  • 1
    Thanks a lot, Chris. This looks along the lines of what I was trying to explain. I will have a play! – Chris Aug 02 '17 at 08:36
  • 1
    @GauravMantri Thanks! We're holding back on doing too much PR about this until we get it into a more stable state (stable, meaning we don't need to introduce any more breaking changes). Stay tuned for the public beta. :) – Chris Gillum Aug 03 '17 at 00:26
  • So, will function 1 wait until function 2 is completed? I try doing something similar, but the webhook (initial event) will complain if my long running process takes to long. I would like to actually 'fire and forget the next function (which is doing the long running process)', possible? – CularBytes Jun 13 '18 at 20:00
  • @CularBytes yes, function 1 will wait for function 2 to complete, but asynchronously in a way that is not impacted by function host timeouts. You are also not billed for "waiting" time in the Consumption plan. However, there isn't a true "fire and forget" semantic. The orchestrator function completes only when all activity functions are done executing. – Chris Gillum Jun 13 '18 at 20:20
5

The recommended pattern for function chaining would be to do use queues (SB/Storage Queues), where one function outputs into another's input queue with a message carrying the payload to be processed.

This keeps your functions small, fast and decoupled, while taking advantage of all the logic in place for provisioning, scaling and fault handling.

Fabio Cavalcante
  • 12,328
  • 3
  • 35
  • 43
  • Good call this, it's called the pipe and filter pattern: https://learn.microsoft.com/en-us/azure/architecture/patterns/pipes-and-filters – Murray Foxcroft Aug 01 '17 at 20:30
  • Thanks Fabio. This would be fine but my messages will exceed the maximum size of messages for Service Bus and Storage Queues. – Chris Aug 02 '17 at 08:29
  • 1
    For that, you do need to employ a pattern similar to what Chris mentioned in his answer and store the actual payload elsewhere (e.g. blob storage) and your queue message would just be a light control message with a reference to that blob. You can also leverage our blob trigger to simplify that for you. – Fabio Cavalcante Aug 02 '17 at 17:48