ServiceBus Trigger not binding CorrelationId - azure

I have an Azure Function which is using a ServiceBus trigger with topics. I recently added correlationId to the list of bindable inputs however the correlationId is not binding. I have confirmed that the correlationId is set corectly on the inbound message. All tooling/NuGets are on the latest bits (as of today).
The function also happens to be a durable function as is obvious in the following code snippet
[FunctionName("TopicHandler")]
public static void Run([ServiceBusTrigger("%TopicName%", "SubscriptionName", Connection = "ServiceBusConnection")]string messageBody,
string label,
string messageId,
string correlationId,
IDictionary<string, object> userProperties,
[OrchestrationClient] DurableOrchestrationClient starter,
ExecutionContext executionContext,
ILogger logger)
{
....
Documetnation seems to imply this should work:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus#trigger---message-metadata
However this is not completely explict as to whether it only works with queues or not.
https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messages-payloads#message-routing-and-correlation
Any guidance would be appreciated before I create a custom property.

Related

How to Pass EventData to Durable Functions?

I want to run durable function from EventHubTrigger azure function.
public async Task<bool> Activities(
[EventHubTrigger(EventHubName, Connection = EventHubConnStrName)] EventData[] events,
[DurableClient] IDurableOrchestrationClient durableClient,
ILogger logger)
{
// chaining pattern durable function
await durableClient.StartNewAsync<string>(
FunctionNames.BatchEvents,
JsonConvertUtil.SerializeObject(events));
}
[FunctionName(FunctionNames.BatchEvents)]
public static async Task<bool> Run(
[OrchestrationTrigger] IDurableOrchestrationContext context,
ILogger logger)
{
try
{
var events =
JsonConvertUtil.DeserializeObject<EventData[]>(context.GetInput<string>()));
....
}
catch (Exception ex)
{
logger.LogError(ex.Message);
throw;
}
}
Let me know how can i pass events to durable function or i can design it better way ?
I believe the way you written the workflow to pass Event data in Azure Durable Functions makes sense after reading this event-based-workflows-with-durable-function.
var events =
JsonConvertUtil.DeserializeObject<EventData[]>(context.GetInput<string>()));
In your code, as you have used context.GetInput<string> Method unpacks the event data you passed and also with deserialization to JSON.
In the above article, there is some information regarding the workflows usage of Event based Triggered Data using in Azure Durable Functions which might help you.

Azure Durable Function: JsonSerializationException by passing complex object from trigger to orchestrator

I have an azure function with EventHubTrigger:
[FunctionName("TradesDataProcessStarterEh")]
public static async Task TradesDataProcessStarterEh([EventHubTrigger("aeehrobotronapiintegrationdev", Connection = "EventHubConnectionString", ConsumerGroup = "$Default")]
EventData eventData, PartitionContext partitionContext, [OrchestrationClient] DurableOrchestrationClient starter, ILogger log)
{
if (partitionContext.PartitionId != "1")
return;
var orchestrationId = await starter.StartNewAsync("O_ProcessTradesFromEventHub", eventData);
await partitionContext.CheckpointAsync();
}
The orchestrator function is receiving then the eventData:
[FunctionName("O_ProcessTradesFromEventHub")]
public static async Task ProcessTradesFromEventHub([OrchestrationTrigger] DurableOrchestrationContext context,
ILogger log)
{
if (!context.IsReplaying)
Console.WriteLine("O_ProcessTradesFromEventHub is triggered");
var eventData = context.GetInput<EventData>();
//do stuff...
}
But by execution of context.GetInput() I get an exception:
Function 'O_ProcessTradesFromEventHub (Orchestrator)' failed with an error. Reason: Newtonsoft.Json.JsonSerializationException: Unable to find a constructor to use for type Microsoft.Azure.EventHubs.EventData. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'Body', line 1, position 81.
I can think of 3 possible solutions that you can try:
1 - Wrap EventData in your own class with a constructor (possibly via inheritance?).
2 - Try casting to object, doubt this will work but, but worth a try as it's a simple fix.
3 - Build your own DTO (Data Transfer Object) to transform EventData to <your class> and then pass <your class> to the orchestration.
I think (3) is the cleanest solution and you have full control over what you pass, unfortunately it is likely the least performant and most tedious.
Good luck!
Use LINQ to JSON - a year later but hopefully it'll save somebody else some time.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public static async Task Run(
[OrchestrationTrigger] DurableOrchestrationContext context, ILogger log) {
var eventData = context.GetInput<JObject>();
log.LogInformation ($"Executing tasks with eventData = {eventData}");
string step = (string)eventData.SelectToken("Step");
log.LogInformation ($"Step = {step}");
}

Azure Function Bindings for Service Bus

I'm following this documentation to create a trigger for a service bus queue.
I'd like to be able to access the message properties. I thought I could simply add Dictionary<string, object> properties to the parameter list like so:
public static void Run(
[ServiceBusTrigger(QueueName, Connection = "connectionSetting")]
// Message message,
string myQueueItem,
Int32 deliveryCount,
DateTime enqueuedTimeUtc,
string messageId,
string ContentType,
Dictionary<string,object> properties,
TraceWriter log)
But that throws:
Error indexing method 'Program.Run'. Microsoft.Azure.WebJobs.Host:
Cannot bind parameter 'properties' to type Dictionary`2. Make sure the
parameter Type is supported by the binding.
Here is a list of the possible parameter bindings. What am I getting wrong?
Update:
I tried changing the singature to
public static void Run(
[ServiceBusTrigger(QueueName, Connection = "connectionSetting")]
// Message message,
string myQueueItem,
Int32 deliveryCount,
DateTime enqueuedTimeUtc,
string messageId,
string ContentType,
IDictionary<string, object> properties,
TraceWriter log)
It produces the same error:
Error indexing method 'Program.Run'. Microsoft.Azure.WebJobs.Host:
Cannot bind parameter 'properties' to type IDictionary
For function v2 runtime, the name of the parameter has changed to UserProperties
To fix the error, update the parameter to the following:
IDictionary<string, object> UserProperties
Here is the related code from Service Bus extension.
https://github.com/Azure/azure-webjobs-sdk/blob/42a711763ddecca9df4caae9c7dc5fe16178880c/src/Microsoft.Azure.WebJobs.ServiceBus/Triggers/ServiceBusTriggerBinding.cs#L127
IDictionary<string, object> properties
Update:
for version 2 use the following bindings:
public static void Run(
[ServiceBusTrigger(QueueName, Connection = "connectionSetting")]
Message message,
string label,
Int32 deliveryCount,
DateTime enqueuedTimeUtc,
string messageId,
string ContentType,
ILogger log)
{
log.LogInformation($"C# ServiceBus queue trigger function processed message: {Encoding.UTF8.GetString(message.Body)}");
var userProperties = message.UserProperties;
}

Azure Function Blob Trigger - Container Name as Setting

I'm trying to create an Azure function that connects to a container that is not hard-coded, much like my connection.
public static void Run(
[BlobTrigger("Container-Name/ftp/{name}", Connection = "AzureWebJobsStorage")]Stream blobStream,
string name,
IDictionary<string, string> metaData,
TraceWriter log)
The connection property is able to get the connection value directly from local.settings.json. It does not appear that capability is an option for "container-name", or if so, not with the appended /ftp/{name}.
So, is there a way to set the container name based on settings for an Azure Function Blob Trigger?
You can define your function like this:
public static void Run(
[BlobTrigger("%mycontainername%/ftp/{name}", Connection = "AzureWebJobsStorage")]
Stream blobStream,
string name,
IDictionary<string, string> metaData,
TraceWriter log)
and then define an application setting called mycontainername to contain the actual container name.

Azure Functions and DocumentDB triggers

Is it possible to specify the DocumentDB is to fire triggers when writing to DocumentDB?
I have an Azure function that pulls JSON messages off a Service Bus Queue and puts them into DocumentDB like so:
using System;
using System.Threading.Tasks;
public static string Run(string myQueueItem, TraceWriter log)
{
log.Info($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
return myQueueItem;
}
This inserts new documents into the database as they are added to the service bus queue, however I need DocumentDB to process these as they are added and add attachments. This cannot be done in the present setup and I would like to tell DocumentDB to fire a trigger.
I have tried something like this:
using System;
using System.Threading.Tasks;
public static string Run(string myQueueItem, TraceWriter log)
{
log.Info($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
return "x-ms-documentdb-post-trigger-include: addDocument\n" + myQueueItem;
}
It doesn't work and gives me errors like this:
Exception while executing function:
Functions.ServiceBusQueueTriggerCSharp1. Microsoft.Azure.WebJobs.Host:
Error while handling parameter _return after function returned:.
Newtonsoft.Json: Unexpected character encountered while parsing value:
x. Path '', line 0, position 0.
I like this setup because I can saturate the queue with requests to add records and they just buffer until the database can deal with it, which deals with spikes in demand, but it allows data offload from the client machine as fast as the network can carry it and then the queue/database combination gets caught up when demand drops again.
You could refer to the following code sample to create document with the trigger enabled in Azure Functions.
using System;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
public static void Run(string myQueueItem, TraceWriter log)
{
string EndpointUri = "https://{documentdb account name}.documents.azure.com:443/";
string PrimaryKey = "{PrimaryKey}";
DocumentClient client = new DocumentClient(new Uri(EndpointUri), PrimaryKey);
client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri("{databaseid}", "{collenctionid}"), new MyChunk { MyProperty = "hello" },
new RequestOptions
{
PreTriggerInclude = new List<string> { "YourTriggerName" },
}).Wait();
log.Info($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
}
public class MyChunk
{
public string MyProperty { get; set; }
}
Note: for using Microsoft.Azure.DocumentDB NuGet package in a C# function, please upload a project.json file to the function's folder in the function app's file system.
project.json
{
"frameworks": {
"net46":{
"dependencies": {
"Microsoft.Azure.DocumentDB": "1.13.1"
}
}
}
}
Besides, please make sure you have created triggers in your DocumentDB, for details about creating triggers, please refer to this article.

Resources