January 14, 2018

Triggering Azure Functions via NodeJS + Storage Queues

Recently I was working on a NodeJS project in Azure. I needed one Azure function to queue messages that another Azure function would be triggered by. Conveniently enough, Azure provides the triggering mechanism out of the box (through the concept of function binding). I was using Storage Queues to hold my messages. These are especially handy when the function being triggered happens to fail or crash and you want to avoid data loss.

NodeJS Function 1 –> Storage Queue –> NodeJS Function 2

Implementation seemed simple enough. Following the example in the azure-storage-node README, I implemented Function 1 with code that looked something like this:

const AzureStorage = require('azure-storage');
const queueService = AzureStorage.createQueueService();

queueService.createMessage('taskqueue', 'Hello world!', function (error) {
  if (!error) {
    // Message inserted
  }
});

Then I went on to implement Function 2 (which bound to the Storage Queue specified in Function 1). My function.json for Function 2 looked something like this:

...
"bindings": [
  {
    "name": "queuedMessage",
    "type": "queueTrigger",
    "queueName": "taskqueue",
    "direction": "in",
    "connection": "AzureWebJobsStorage"
  }
],
...

Implementing the application code is simple.

module.exports = function (context, queuedMessage) {
  context.log(queuedMessage);
  context.done();
};

At this point, I invoked Function 1 to insert a test message into the queue. This was successful. Turning to Function 2, I saw that it was invoked by the message inserted into the queue. Although Function 2 executed, it immediately threw an error:

Exception while executing function: Functions.Function2. Microsoft.Azure.WebJobs.Host: Exception binding parameter 'queuedMessage'. mscorlib: The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.

After a bit of head scratching and a fair bit of Googling, I discovered that there is an inconsistency between how messages are encoded (by default) via azure-storage-node and how they are decoded via NodeJS function triggers.

Confusingly, the azure-storage-node library defaults to using the TextXmlQueueMessageEncoder, whereas the Azure NodeJS function trigger expects messages to be encoded via the TextBase64QueueMessageEncoder.

The solution was simple once I understood this. At this point, I modified Function 1 to instead look like:

const AzureStorage = require('azure-storage');
const QueueMessageEncoder = AzureStorage.QueueMessageEncoder;

var queueService = AzureStorage.createQueueService();
queueService.messageEncoder = new QueueMessageEncoder.TextBase64QueueMessageEncoder();
queueService.createMessage('taskqueue', 'Hello world!', function(error) {
  if (!error) {
    // Message inserted
  }
});

And with that change, Function 1 will now insert Base64 encoded messages into the queue. Function 2 will now happily consume these messages without crashing.

-Eric

© Eric Barch 2023