2

In a previous discussion thread (How to output multiple blobs from an Azure Function?) it was explained to me how to use imperative binding to output multiple blobs from a single Azure Function invocation. I have had partial success with that approach, and need guidance on diagnosing this problem. My function triggers on a blob, processes it, and generates multiple output blobs. Basically it is partitioning a big data table by date.

When I trigger it with a small blob (8K) it works fine. When I process a bigger blob (2M), all the logging in the Function indicates that it was successful, but the function monitor blade shows that it failed:

Failure: The operation was canceled.

Again, the Function log has all my logging and no errors.

The invocation that succeeded took 1785ms.

The invocation that failed multiple entries in the invocation log (I assume because the blog didn't get marked as processed). Their times are all around 12,000ms. That time is well within the five minute limit for a function.

I assume that I've hit some limit with imperative binding timing out. I am seeking guidance on how to diagnose and resolve this problem. The files I actually have to process are up to 20M so will take even longer to process but would still be under 5 minutes.

function.json:

{
  "bindings": [
    {
      "name": "myBlob",
      "type": "blobTrigger",
      "direction": "in",
      "path": "dms/{blobname}",
      "connection": "deal2_STORAGE"
    },
    {
      "type": "queue",
      "name": "emailQueueItem",
      "queueName": "emailqueue",
      "connection": "deal2_STORAGE",
      "direction": "out"
    }
  ],
  "disabled": false
}

run.csx

public static async Task Run(Stream myBlob, string blobname, IAsyncCollector<string> emailQueueItem, Binder binder, TraceWriter log)

{
  ...

    try {

    ...

        foreach (var dt in dates) {
                blobPath = $"json/{fileNamePart}_{dateString}";
                var attributes = new Attribute[] {
                  new BlobAttribute(blobPath),
                  new StorageAccountAttribute("deal2_STORAGE")
                };

                using (var writer = await binder.BindAsync<TextWriter>(attributes).ConfigureAwait(false)) {
                    writer.Write( jsonString.ToString() );
                }

        }

        ...

        await emailQueueItem.AddAsync( $"{{\"script\":\"DmsBlobTrigger\",\"tsvFileName\":\"{tsvFileName}\",\"status\":\"{retval}\",\"message\":\"{statusMessage}\"}}" );

    } catch (Exception excp) {
        Logger.Info(excp.ToString());
    }

}
Community
  • 1
  • 1
Chris Harrington
  • 1,238
  • 2
  • 15
  • 28
  • As you see from the code, the incoming blob and outgoing blob and queue are all using the same storage account. I wonder if splitting them up might help? But what I find most disconcerting is to get "The operation was canceled." without any further information. – Chris Harrington Feb 15 '17 at 01:03
  • please try to put try-catch in your foreach loop, and log and output error. ``foreach (var dt in dates) { try { blobPath = $"json/{fileNamePart}_{dateString}"; //your code log.Info($"json/{fileNamePart}_{dateString}); } catch (Exception ex) { log.Info("error while creating " + $"json/{fileNamePart}_{dateString} + "; error message: " + ex.Message); } } ``and check if the code throw exception while creating some output blob. – Fei Han Feb 15 '17 at 09:31
  • Hi Fred. I put a try/catch inside the foreach. No exceptions were thrown. Still fails with "the operation was canceled". – Chris Harrington Feb 16 '17 at 14:50
  • Instead of a `foreach ... { await BindAsync }` loop, can you create a separate task for each attribute and use Task.WhenAll? I think that might increase parallelism, right now it seems that every upload will process sequentially. – Matt Mason Feb 16 '17 at 18:54
  • I will try that. But I'd still like to understand (and report to my superiors) what is the root cause. What's the problem with it processing sequentially? And what does "The operation was canceled" mean? – Chris Harrington Feb 17 '17 at 03:04
  • Looking at samples of Task.WhenAll() and at the binder.BindAsync, I have no idea how to refactor my code to use Task.WhenAll(). Hits please? – Chris Harrington Feb 17 '17 at 03:54

0 Answers0