0
votes

My scenario: with a message coming from an Azure Storage Queue I want to either create or update a document in DocumentDB

  • I set the DocumentDB consistency to Strong, so that it is guaranteed that the document is updated
  • I use a Singleton/Listener, so that only one Queue entry is processed at a time

Here is my code:

function.json

{
  "disabled": false,
  "bindings": [
    {
      "name": "updateEntry",
      "type": "queueTrigger",
      "direction": "in",
      "queueName": "update-log",
      "connection": "AzureWebJobsStorage"
    },
    {
      "type": "documentDB",
      "name": "inputDocument",
      "databaseName": "logging",
      "collectionName": "messages",
      "id": "{id}",
      "connection": "documentDB",
      "direction": "in"
    },
    {
      "type": "documentDB",
      "name": "outputDocument",
      "databaseName": "logging",
      "collectionName": "messages",
      "createIfNotExists": true,
      "connection": "documentDB",
      "direction": "out"
    }
  ]
}

run.csx

#r "Newtonsoft.Json"

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

[Singleton(Mode = SingletonMode.Listener)]
public static void Run(UpdateEntryType updateEntry, TraceWriter log, DocumentType inputDocument, out DocumentType outputDocument)
{
    log.Info($"update entry:{updateEntry.id} {updateEntry.created} {updateEntry.Event.ToString()}");

    outputDocument = new DocumentType();
    outputDocument.Events = new List<JObject>();

    if (inputDocument == null)
    {
        outputDocument.id = updateEntry.id;
        outputDocument.created = updateEntry.created;
    }
    else
    {
        log.Info($"input document:{inputDocument.id} {inputDocument.created} {inputDocument.Events.Count}");
        outputDocument.id = inputDocument.id;
        outputDocument.created = updateEntry.created.CompareTo(inputDocument.created) < 0 ? updateEntry.created : inputDocument.created;
        outputDocument.Events.AddRange(inputDocument.Events);
    }

    outputDocument.Events.Add(updateEntry.Event);

    log.Info($"output document:{outputDocument.id} {outputDocument.created} {outputDocument.Events.Count}");
}

public class UpdateEntryType
{
    public string id { get; set; }
    public string created { get; set; }
    public JObject Event { get; set; }
}

public class DocumentType
{
    public string id { get; set; }
    public string created { get; set; }
    public List<JObject> Events { get; set; }
}

My problem: most of the times an actual existing document is found with id and hence updated - but not for at least 5% of the time

My questions (before I open a case @MSFT support): What am I missing? Is this the right approach or is it destined to fail anyway?

2

2 Answers

1
votes

not for at least 5% of the time

From my experience, If it is a dedicated plan, we need to turn on Always On setting for our Function App.

The Function runtime will go idle after a few minutes of inactivity, so only HTTP triggers will actually "wake up" your functions. This is similar to how WebJobs must have Always On enabled.

More detail info about Consumption Plan & Dedicated App Service Plan and how to set appsetting, please refer to Enable Always On when running on dedicated App Service Plan.

enter image description here

1
votes

Using Queue batchSize 1 instead of SingletonMode.Listener made the problem disappear.

hosts.json

{
  "queues": {
    "batchSize": 1
}