How to call Azure Functions based on the Function Slots - azure

I had multiple Azure Functions which are deployed in different Azure Function slots. The functions are called based on the CloudStorage QueueMessage as below.
// Get storage account
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(Microsoft.Azure.CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Next, create a queue client
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
// Then retrieve a reference to a queue – here’s where you give your queue a name
CloudQueue queue = queueClient.GetQueueReference(queueName);
// Create the queue if it doesn’t already exist
queue.CreateIfNotExists();
// Penultimate step – create a message and add it to the queue.
CloudQueueMessage message = new CloudQueueMessage(bordereauxId.ToString());
// Finally, add your message to the queue
queue.AddMessage(message);
// Fetch the queue attributes.
queue.FetchAttributes();
Is there any way to queue the message based on the Slots. For example, if the user is using development site then the function queue should call the function that belongs to Devlopment Slot using the same storage account.

As #MurrayFoxcroft suggested, you should use per-slot App Settings to configure your storage accounts per App Slot.
To add, you should replace all the code you are quoting with an Storage Queue output binding:
{
"type": "queue",
"direction": "out",
"name": "$return",
"queueName": "outqueue",
"connection": "StorageConnectionString",
}
Then the function will just return the queue message (you can use out params too).
StorageConnectionString should be an app setting pinned to App Slot.

You can determine if your function is running in a slot by using the following:
var slot = System.Environment.GetEnvironmentVariable("APPSETTING_WEBSITE_SLOT_NAME", EnvironmentVariableTarget.Process);
You can then use the result to direct your code down the correct path.
However, where possible, I'd avoid coding in logic to handle different scenarios based on slot. Try to drive your logic from configuration where possible. For example, in your AppSettings you can configure sticky settings (Slot Settings) to provide configuration per slot.
When running locally you should be using the Azure Functions Core Tools for debugging. See this link. Put your sample app settings in localsettings.json to test your function. Change them appropriately or use multiple files to simulate your slots.

I got the solution by making the queue name based on the slots
So in my console application now the queue name is based on the slot I want to call and added in the config file.
// Then retrieve a reference to a queue – here’s where you give your queue a name
CloudQueue queue = queueClient.GetQueueReference(queueName + "_" + slotname);
And the queue name in the function is defined based on the slot application settings
Hence in the Azure function method the queue name will be defined as below
public static void Run([QueueTrigger("%slot_queue_name%", Connection = "AzureWebJobsStorage")]string myQueueItem)
Where the "slot_queue_name" will be defined in the Azure Function slot Application settings.

Related

Deploying same Azure cloud function for each environment - dev, qa, prod

Have a function app with single cloud function in it. The cloud function is triggered by an HTTP call and pushes the payload to a Azure service bus queue. What needs to be done is, as part of automated deployment, would like to have few variables configured per environment -
Function Name
Queue Name
Queue Connection String
Deployment is to be done using Azure DevOps. Function code is also on Azure DevOps repository which will have branch for each environment, so will need function with different function name for eg - Dev_Function, QA_Function,etc since it needs to connect to corresponding environment queue. Also aware that variables can be configured using App Settings on Azure portal. Any help/insights appreciated!
i think you could keep the function name as it is and change make the Queue name and Connection string to be pickup from Azure function app service configuration.
[FunctionName("SendEmailFunc")]
public static async Task SendEmailFunc([QueueTrigger($"%{FuncAppConstants.Queue.EmailQueueName}%")] EmailMessage emailMessage)
{
}
you can get the queue name at runtime by using this
[QueueTrigger($"%prod_queue_name%")]
and configuration will just look like below in the local.setting.json
"prod_queue_name": "test-email-queue"
and similarly in the Azure function app configuration
And same can be done for the connection string

Azure Function is not triggerd after putting a message to a queue in service bus

I have a queue in a service bus. After putting a message into a queue an azure logic app and an azure functions should betriggered and process the content.
My Azure logic app is triggered but my azure funcction is not triggered. My code for azure function:
[FunctionName("ReadMEssageFromQueue")]
public static void Run([ServiceBusTrigger("messagequeue", Connection = "AzureWebJobsStorage")]string myQueueItem, ILogger log)
{
log.LogInformation($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
}
host json:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"AzureWebJobsStorage": "******" // connection string of my service bus
}
}
should I set something in service bus queue to send message to both ressources?
Azure Service Bus Queue messages are picked up by only one processor. So I think in your case, the logic app is picking up and consuming the message first and the message is not available for the function to process. You can try temporarily disabling the logic app and letting function pick the message to confirm this.
Ref: azure-service-bus-queue-with-multiple-listeners
You can trigger the Azure function from your logic app (not sure if it'll help your use case), or you can use Azure Service Bus topics as topics support the model where multiple consumers can subscribe to a topic.
The former option might be a better approach for you from cost perspective, as you'd need to use Standard tier of service bus in order to use topics feature, which means additional cost for you over your current setup.
Also, you might want to use some other name for service bus connection string as AzureWebJobsStorage is used for storage account connection string

Disabled Azure Function Still Pulls Messages off of Azure Storage Queue

I have a basic QueueTrigger Azure function. When I disable the function in the azure portal it's still pulling messages off the storage queue (because when I look at the queue in the Azure Queue Storage Explorer the queue is empty and if i add a message it is immediately pulled off).
Here is the code:
[FunctionName("ProcessMessage")]
public static void Run([QueueTrigger("queue-name", Connection = "queue-connection")] Models.Message message, TraceWriter log)
{
log.Info($"C# Queue trigger function processed: {message}");
}
I noticed that when I stop the whole functions app it stops processing messages off the queue, but I was hoping that I could disable queue processing temporarily without stopping the whole function app. How does one do that?
Thanks!
Disabling the V1 function created in Visual Studio does not work in the azure portal. You should use the attribute:
https://learn.microsoft.com/en-us/azure/azure-functions/disable-function#functions-1x---c-class-libraries
(see important section)

Azure alerting rule for poison queue count

In a pervious project I have managed to setup a Alert rule that looks at poison queue message count and alerts using a webhook into slack when something is in the queue (once per day).
I was trying to find where this exists in Azure as it looks like things have moved around. If this is not a feature provided by azure could you give guidance on what's the best route in implementing something similar.
Thanks
I was trying to find where this exists in Azure as it looks like things have moved around. If this is not a feature provided by azure could you give guidance on what's the best route in implementing something similar.
As far as I know, currently there is no a feature provided by azure to send the a alert rule to check the poison queue count.
You need write you own logic to achieve this requirement.
I suggest you could considerusing webjob/azure function timer trigger or queue trigger.
If you want to check the poison count every 5 minutes(for example), you could choose timer trigger.
Then in the timer trigger method, you could use ApproximateMessageCount method to get the queue messages' count.
At last, you could use sendgrid to send the notification email to special account.
Codes:
//get the storage account from the connection string
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
//instantiate the client
CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
CloudQueue q = queueClient.GetQueueReference("queue-poison");
q.FetchAttributes();
var qCnt = q.ApproximateMessageCount;
If you want to get the count when the new queue message has added into the poison queue. You could choose queue trigger. The codes is as same as the timer trigger, just change the parameters.

Parallel Blob processing with Azure WebJobs

I have multiple instances of a WebSite, all running the same WebJob, connected to the same AzureWebJobsStorage and configured to trigger on incoming blobs.
Unfortunetely, the result is different from what I intended - when a blob is saved to the storage, only one of the WebJobs instances picks it up. I would rather have all of them process this blob. My guess is that it works like this beacuse of how the blob receipt name is constructed - it contains the WebJob funcion name which is the same for all my WebJobs.
Is there any way to have the blob processed by all WebJob instances in this situation?
I just found an answer to this question by myself. It turns out that one can configure the HostId which gets included in the blob's receipt name. For me, the following piece of code does the job:
var applicationName = Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME");
var host = new JobHost(new JobHostConfiguration
{
HostId = applicationName ?? "localhost"
});

Resources