I'm trying to follow the documentation to write a message to an Azure Service Bus queue from an Azure Function (https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus-output?tabs=csharp).
I started off with the "File->New Project" for an HTTP Trigger and added the binding:
[FunctionName("Message")]
[return: ServiceBus("namequeue")]
public static async Task<string> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
string name = data?.name ?? "DefaultName";
return name;
}
My host.json and local.settings.json file contains:
"extensions": {
"serviceBus": {
"prefetchCount": 100,
"messageHandlerOptions": {
"autoComplete": true,
"maxConcurrentCalls": 32,
"maxAutoRenewDuration": "00:05:00"
},
"sessionHandlerOptions": {
"autoComplete": false,
"messageWaitTimeout": "00:00:30",
"maxAutoRenewDuration": "00:55:00",
"maxConcurrentSessions": 16
},
"batchOptions": {
"maxMessageCount": 1000,
"operationTimeout": "00:01:00",
"autoComplete": "true"
}
}
},
"Values": {
"AzureWebJobsServiceBus": "Endpoint=<redacted>"
}
When running locally I get a timeout exception (which might be a corporate firewall).
When deployed to Azure, I can POST to the function, get a 204 reply, but no messages are added to the queue.
I think I've missed a key step as my function.json in the Azure Portal has:
{
"generatedBy": "Microsoft.NET.Sdk.Functions-3.0.13",
"configurationSource": "attributes",
"bindings": [
{
"type": "httpTrigger",
"methods": [
"post"
],
"authLevel": "anonymous",
"name": "req"
}
],
"disabled": false,
"scriptFile": "../bin/AppMapServiceBusCreate.dll",
"entryPoint": "AppMapServiceBus.CreateMessageFunction.Run"
}
And when I click on Integration within the Portal there are no output and adding one gives me a warning of "In order to see the entire list of available function templates, you must set up extension bundles for your app.".
I thought Extension Bundles were non .NET code and the fact I've added the following via NuGet did the same thing?
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus" Version="4.3.0" />
If that's accurate, how/what do I add to the function.json?
For Azure Functions using an output trigger to write to Service Bus, you'll need to add the connection string as an application setting in the function's configuration. By default, the expected setting name is AzureWebJobsServiceBus:
Related
I am trying to use the standard ILogger and make it log to Azure. First I added following to host file:
{
"version": "2.0",
"Logging": {
"ApplicationInsights": {
"LogLevel": {
"Default": "Trace",
"System": "None",
"Microsoft": "None"
}
}
},
"ApplicationInsights": {
"Instrumentationkey": "xx-xx-xx-xx-xx"
}
}
And this is my function:
namespace Jobs
{
public static class ExchangeRates
{
[FunctionName("ExchangeRates")]
public static void Run([TimerTrigger("0 0 0 * * *", RunOnStartup =true)]TimerInfo myTimer, ILogger log)
{
string lol1 = "lol1 text";
string lol2 = "lol2 text";
log.LogWarning("adsad");
log.LogDebug("LogDebug", "asdasd", lol2);
log.LogTrace("LogTrace {lol1}, {lol2}", lol1, lol2);
log.LogInformation("LogInfo {lol1}, {lol2}", lol1, lol2);
log.LogError("LogError");
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
}
}
}
But no logging are added. I also tried installing nuget package:
Microsoft.Extensions.Logging.ApplicationInsights
Am I missing something - what does it take to make an function app writing to Application Insights?
I think you're running the azure function locally with application insights, right?
If yes, actually it's not recommended since application insights is integrated with azure function in azure portal.
But for testing only, you can just add this line of setting "APPINSIGHTS_INSTRUMENTATIONKEY": "the key" in local.settings.json(remember to set it as "copy if newer"). The sample settings in local.settings.json looks like below:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "xxxxxx",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"APPINSIGHTS_INSTRUMENTATIONKEY": "the key"
}
}
By the way, I also installed the nuget package Microsoft.Extensions.Logging.ApplicationInsights in my test.
I have a simple HTTP trigger Azure Function with multiple Service Bus output bindings. All the bindings are pointing to the same Topic, but they have different Subscriptions. If I was to set this function app through function.json it is pretty straightforward:
{
"bindings": [
{
"authLevel": "function",
"name": "req",
"type": "httpTrigger",
"direction": "in",
"methods": [
"get",
"post"
]
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"type": "serviceBus",
"connection": "SERVICEBUS",
"name": "output",
"topicName": "outtopic",
"subscriptionName": "sub",
"direction": "out"
},
{
"type": "serviceBus",
"connection": "SERVICEBUS",
"name": "output",
"topicName": "outtopic",
"subscriptionName": "sub2",
"direction": "out"
}
],
"disabled": false
}
But I publish my functions via Visual Studio and therefore my Azure Functions are read only in the portal and function.json is automatically generated by VS upon publishing.
The problem is that I cannot figure out how do I setup multiple output bindings pointing to different subscriptions. Currently I have something like this:
[FunctionName("Function2")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
[ServiceBus("outtopic", entityType:EntityType.Topic)] IAsyncCollector<string> output,
[ServiceBus("outtopic", entityType: EntityType.Topic)] IAsyncCollector<string> output2,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
await output.AddAsync(requestBody);
return new OkObjectResult("OK");
}
As you can see output and output2 are pointing to the same Topic, but there is no option to specify Subscription.
At this point I am pretty confident that this has not been implemented yet. But I hope there is a workaround maybe?
Try this, add Connection property in the definition, per this example - if by subscription you mean on the azure subscription:
public static void Run([BlobTrigger("inputvideo/{customername}/{date}/{filename}", Connection = "AzureWebJobsStorage")]Stream myBlob,
string customername,
string date,
string filename,
[ServiceBus("detectobjectsqueue",EntityType.Queue, Connection="ServiceBusConnectionString")] IAsyncCollector<string> output,
ILogger log)
Update
Per your comment, I understood that by subscription you mean on topic subscription. In that case, the idea of topic is that all subscriptions receive the message. So you have one publisher, and whoever subscribes to the topic it will receive the message. If you would like to make sure that a specific subscriber receives the message, either implement message filtering(per type for example) on the receiving endpoint or use dedicated queue per subscriber.
Also, conceptually, the publisher should not know who are the subscribers, and the subscriber should not know who is the publisher. If you know who is the subscriber, why not use the REST call for example to the receiving endpoint?
It is not possible to directly put messages into a Topic Subscription, rather every message has to come through a Topic.
To make sure only a particular subscription receives a message, you need to configure the Topic Subscription rule. You can read more about rules in the blog post here.
We know the Connection string for event hub can be used from local.setting.json file. So for the same function app in different environments, I can add the event hub connection string setting in Application settings in the azure portal.
As the EventHubTrigger function app also expects event name and consumer group(optional) as attributes parameters, I was wondering how the event hub name and consumer group can be used from app settings?
public static void EventHubTriggerFunc([EventHubTrigger("myeventhubname", Connection = "EventHubConnectionAppSetting", ConsumerGroup = "myconsumergroupname")] EventData myEventHubMessage, DateTime enqueuedTimeUtc, Int64 sequenceNumber, string offset, ILogger log)
{
// Here EventHubConnectionAppSetting is specified in local.setting.json file
//myeventhubname & myconsumergroupname are hard coded string
}
local.settings.Json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"EventHubConnectionAppSetting": "Endpoint=.....",
"EventHubConsumerGroup": "myconsumergroup"
}
}
([EventHubTrigger("%myeventhubname%", Connection = "EventHubConnectionAppSetting", ConsumerGroup = "%myconsumergroupname%")]
Tried #Roman Kiss answer, and applied it to Python Azure Functions and it works.
In function.json:
{
"scriptFile": "__init__.py",
"bindings": [
{
"type": "eventHubTrigger",
"name": "events",
"direction": "in",
"eventHubName": "%EVENT_HUB_NAME%",
"connection": "EVENT_HUB_CONN_STR",
"cardinality": "many",
"consumerGroup": "$Default",
"dataType": "binary"
}
]
}
Notice that connection string does not need %
In local.settings.json:
{
...
"Values": {
...
"EVENT_HUB_NAME": "<actual name of event hub>",
"EVENT_HUB_CONN_STR": "Endpoint=sb://...;SharedAccessKeyName=...;SharedAccessKey=...",
...
},
}
Is it possible to invoke cosmos db trigger in azure pipeline? Pipeline is just copy data from azrue storage to cosmos db collection and it is necessary to invoke pre trigger. How to specify trigger id for copy activity?
From what you are saying, you might solve this by using Azure Functions with a Blob Trigger and a DocumentDB output binding.
With a functions.json similar to:
{
"disabled": false,
"bindings": [
{
"name": "myBlob",
"type": "blobTrigger",
"direction": "in",
"path": "<name-of-the-folder-where-files-get-uploaded>",
"connection":"MyStorageAccount"
},
{
"name": "documentToSave",
"type": "documentDB",
"databaseName": "MyDatabase",
"collectionName": "MyCollection",
"createIfNotExists": true,
"connection": "MyAccount_COSMOSDB",
"direction": "out"
}
]
}
And the function body could be something like:
// Blob trigger binding to a CloudBlockBlob
#r "Microsoft.WindowsAzure.Storage"
using Microsoft.WindowsAzure.Storage.Blob;
public static void Run(CloudBlockBlob myBlob, out object documentToSave, TraceWriter log)
{
// some logic to read the blob and parse it
documentToSave = new {
id = "some value",
.. other properties here
};
}
Trying to figure out how to use SendGrid from an azure function. Not much docs to find, but this is what I've tried:
#r "SendGrid"
using SendGrid.Helpers.Mail;
using System;
public static void Run(string myQueueItem, out Mail message, TraceWriter log)
{
log.Info($"C# Queue trigger function processed: {myQueueItem}");
message=new Mail();
}
I've hardcoded to, from, subject and body, together with api key in the integrate output section. This is my function.json:
{
"bindings": [
{
"name": "myQueueItem",
"type": "queueTrigger",
"direction": "in",
"queueName": "send-email-request",
"connection": "myStorage"
},
{
"type": "sendGrid",
"name": "message",
"apiKey": "SG.xxxxxxxxxxx",
"direction": "out",
"to": "me#gmail.com",
"from": "me#gmail.no",
"subject": "hardcoded",
"text": "test213"
}
],
"disabled": false
}
I get the following error:
Function ($SendEmailOnQueueTriggered) Error: Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.SendEmailOnQueueTriggered'. Microsoft.Azure.WebJobs.Host: 'SG.xxxxxx' does not resolve to a value.
Session Id: 9426f2d7e4374c7ba7e0612ea5dc1814
Timestamp: 2017-01-07T12:18:01.930Z
I've granted the Apikey full access in SendGrid. Any ideas what I've missed?
Larsi
The ApiKey field is not the actual ApiKey, it should instead be the name of an AppSettings key defined in the "functions app settings".
Adding "AzureWebJobsSendGridApiKey" in your AppSettings via local.settings.json and in Configuration -> Application Setting via Azure Portal will work.