After some experimentation I realised that I had forgotten that the order of message processing was important e.g. a TTI Queued message should be processed before the associated Ack. This could (and did happen) because I had a queue for each message type and in addition the Azure Queue Storage trigger binding would use parallel execution to process backlogs of messages. My approach caused issues with both intra and inter queue message ordering
namespace devMobile.IoT.TheThingsIndustries.HttpInputStorageQueueOutput
{
using System.Net;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
[StorageAccount("AzureWebJobsStorage")]
public static class Webhooks
{
[Function("Uplink")]
public static async Task<HttpTriggerUplinkOutputBindingType> Uplink([HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req, FunctionContext context)
{
var logger = context.GetLogger("UplinkMessage");
logger.LogInformation("Uplink processed");
var response = req.CreateResponse(HttpStatusCode.OK);
return new HttpTriggerUplinkOutputBindingType()
{
Name = await req.ReadAsStringAsync(),
HttpReponse = response
};
}
public class HttpTriggerUplinkOutputBindingType
{
[QueueOutput("uplink")]
public string Name { get; set; }
public HttpResponseData HttpReponse { get; set; }
}
...
[Function("Failed")]
public static async Task<HttpTriggerFailedOutputBindingType> Failed([HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req, FunctionContext context)
{
var logger = context.GetLogger("Failed");
logger.LogInformation("Failed procssed");
var response = req.CreateResponse(HttpStatusCode.OK);
return new HttpTriggerFailedOutputBindingType()
{
Name = await req.ReadAsStringAsync(),
HttpReponse = response
};
}
public class HttpTriggerFailedOutputBindingType
{
[QueueOutput("failed")]
public string Name { get; set; }
public HttpResponseData HttpReponse { get; set; }
}
}
}
Azure Functions Desktop Development environment running my functions
I used Telerik Fiddler with some sample payloads to test my application.
Telerik Fiddler Request Composer “posting” sample message to desktop endpoint
Once the functions were running reliably on my desktop, I created an Azure Service Plan, deployed the code, then generated an API Key for securing my HTTPTrigger endpoints.
Azure Functions Host Key configuration dialog
I then added a TTI Webhook Integration to my TTI SeeduinoLoRaWAN application, manually configured the endpoint, enabled the different messages I wanted to process and set the x-functions-key header.
TTI Application Webhook configuration
After a short delay I could see messages in the message uplink queue with Azure Storage Explorer
Azure Storage Explorer displaying content of my uplink queue
Building a new version of my TTIV3 Azure IoT connector is a useful learning exercise but I’m still deciding whether is it worth the effort as TTI has one now?