I have an Azure Function with a Timer trigger. The schedule is "*/6 * * * *" (running every six minutes). I cannot run it manually and it does not fire automatically. Below is my function.json:
{
"generatedBy": "Microsoft.NET.Sdk.Functions-1.0.31",
"configurationSource": "attributes",
"bindings": [
{
"type": "timerTrigger",
"schedule": "%TimerTriggerPeriod%",
"useMonitor": true,
"runOnStartup": false,
"name": "myTimer"
}
],
"disabled": false,
"scriptFile": "../bin/AccessChangeMonitoring.dll",
"entryPoint": "Microsoft.IT.Security.AccessChangeMonitoring.AccessChangeMonitoring.InitiateChangeMonitoring"
}
%TimerTriggerPeriod% is defined in my local.settings.json file ("TimerTriggerPeriod": "0 */6 * * * *"). Looking at the Application Function Count metric display on the dashboard, it shows that my function has been executed 0 times:
Below is my host.json:
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingExcludedTypes": "Request",
"samplingSettings": {
"isEnabled": true
}
}
},
"functionTimeout": "00:07:00"
}
Below is the function code:
[FunctionName("InitiateChangeMonitoring")]
public static async Task InitiateChangeMonitoring([TimerTrigger("%TimerTriggerPeriod%")] TimerInfo myTimer, ILogger log)
{
log.LogInformation("Change Monitoring started.");
// Reset the listing of app ids we need to retrieve delta role assignments for
oneAuthZAppIds = new List<string>();
await GetOneAuthZAppIdsAsync();
// Create the necessary Cosmos DB infastructure
await CreateDatabaseAsync();
await CreateContainerAsync();
await CreateDeltaAPICallDatabaseAsync();
await CreateDeltaAPICallContainerAsync();
await CreateManagerMappingDatabaseAsync();
await CreateManagerMappingContainerAsync();
// Compute the authentication token needed to access the PAP Service API
log.LogInformation("\nRetrieve PAPServiceAPIToken");
string PAPServiceAPIToken = await GetTokenAsync(Environment.GetEnvironmentVariable("OneAuthZAppUri"), Environment.GetEnvironmentVariable("OneAuthZAppId"),
PAPAuthenticationSecret);
log.LogInformation("PAPServiceAPIToken = " + PAPServiceAPIToken);
string GraphAPIAuthenticationToken = await GetTokenAsync(Environment.GetEnvironmentVariable("GraphAppUri"), Environment.GetEnvironmentVariable("GraphClientId"),
graphKey);
log.LogInformation("graphAPIAuthenticationToken = " + GraphAPIAuthenticationToken);
await runChangeMonitoringSystemAsync(PAPServiceAPIToken);
}
First, I notice you specify you are using local.settings.json to save the environment variable and at the same time you show the metric on azure.
So, I think the first problem why your azure function can not be triggered is because you don't set the environment variable on azure.
You should set in this place instead of local.settings.json (because when a function is deployed to Azure, it will never take environment variable from local.settings.json):
(Don't forget to save the edit.)
Second, as Ivan says, your format of cron is wrong. The format of timetrigger should be in this format:
{second} {minute} {hour} {day} {month} {day of week}
Related
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:
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 am trying to setup a timerTrigger azure function
My function.json:
{
"disabled": false,
"bindings": [
{
"type": "timerTrigger",
"direction": "in",
"name": "sampleCronTrigger",
"schedule": "*/5 * * * * *",
}
],
"entryPoint": "sampleCron",
"scriptFile": "index.js"
}
In this I need to set an environment variable, but I am not able to do so. I tried looking for some documentation but couldn't find anything which doesn't require some setup on the Azure console?
I can I define environment variables? Or If here is any way I can pass an input to the function, that works too.
App settings in a function app contain global configuration options that affect all functions for that function app. When you run locally, these settings are accessed as local environment variables.
Local settings file
The file local.settings.json stores app settings, connection strings, and settings for Azure Functions Core Tools. Settings in the local.settings.json file are only used by Functions tools when running locally. By default, these settings are not migrated automatically when the project is published to Azure. Use the --publish-local-settings switch when you publish to make sure these settings are added to the function app in Azure.
In Functions, app settings, such as service connection strings, are exposed as environment variables during execution. You can access these settings using process.env, as shown here in the GetEnvironmentVariable function:
module.exports = function (context, myTimer) {
var timeStamp = new Date().toISOString();
context.log('Node.js timer trigger function ran!', timeStamp);
context.log(GetEnvironmentVariable("AzureWebJobsStorage"));
context.log(GetEnvironmentVariable("WEBSITE_SITE_NAME"));
context.done();
};
function GetEnvironmentVariable(name)
{
return name + ": " + process.env[name];
}
There are several ways that you can add, update, and delete function app settings:
From Azure portal.
By using the Azure CLI.
When running locally, app settings are read from the local.settings.json project file.
References:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-app-settings
https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node#environment-variables
https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node#environment-variables
Additionally for retrieving values from local.settings.json, another way is to create an IConfigurationRoot object using ExecutionContext executionContext.
ExecutionContext can be added to function definition:
[FunctionName("FunctionName")]
public static async Task Run(
[ServiceBusTrigger(...)]
SomeMessage msg,
ILogger log,
ExecutionContext executionContext)
{
}
After that, you can instantiate an IConfigurationRoot instance, which you instruct to optionally load local.appsettings.json.
var configurationRoot = new ConfigurationBuilder()
.SetBasePath(executionContext.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
With the configurationRoot object, you can retrieve configuration values:
var value = configurationRoot["SomeKey"];
Example local.settings.json:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "...",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"SomeKey": "Value",
},
"Host": {
"LocalHttpPort": "7071"
}
}
I have the following C# function code:
[FunctionName("UpdateCohortsByTenantFunction")]
[return: Queue("my-queue", Connection = "MyStorage")]
//note - I have tried both method decoration and parameter decoration
public static async Task Run([TimerTrigger("* * * * * *")]TimerInfo myTimer, IAsyncCollector<AudienceMessage> output)
{
//some logic
foreach (var audience in audiences)
{
await output.AddAsync(new AudienceMessage
{
AudienceId = audience.Id,
TenantId = tenant.Id
});
}
}
Which produces the following function.json:
{
"generatedBy": "Microsoft.NET.Sdk.Functions.Generator-1.0.6",
"configurationSource": "attributes",
"bindings": [
{
"type": "timerTrigger",
"schedule": "* * * * * *",
"useMonitor": true,
"runOnStartup": false,
"name": "myTimer"
}
],
"disabled": false,
"scriptFile": "../bin/MyApp.App.Tasks.Functions.dll",
"entryPoint": "MyApp.App.Tasks.Functions.UpdateCohortsByTenantFunction.Run"
}
According to the documentation here the json output should contain an binding to my queue with an "out" direction. Ie:
{
"type": "queue",
"direction": "out",
"name": "$return",
"queueName": "outqueue",
"connection": "MyStorageConnectionAppSetting",
}
When I try to run the queue via the npm tools (config described here), I get the following error:
Run: Microsoft.Azure.WebJobs.Host: Error indexing method 'UpdateCohortsByTenantFunction.Run'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'output' to type IAsyncCollector`1. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. config.UseServiceBus(), config.UseTimers(), etc.).
The documentation contains no references to binding via startup code. My understanding is that this is done via the attributes described in the Microsoft documentation linked above, and in my example code, but the error message suggests otherwise.
You should decorate your parameter with attribute, not return value:
public static async Task Run(
[TimerTrigger("* * * * * *")]TimerInfo myTimer,
[Queue("my-queue", Connection = "MyStg")] IAsyncCollector<AudienceMessage> output)
No output binding in function.json is to be expected. Attribute-defined bindings are not transferred to generated function.json. They will still work, don't worry.
I am trying to use Azure function with to invoke the same function with different time and different param(url).
I didn't find any good example that shows how to pass some data. I want to pass link to function.
My code is:
var rp = require('request-promise');
var request = require('request');
module.exports = function (context //need to get the url) {
and the function
{
"bindings": [
{
"name": "myTimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 0 */1 * * *"
}
],
"disabled": false
}
If your settings are relatively static (but you still don't want to hard code them), you may use app settings to store them, and then read e.g.
let url = process.env['MyUrl'];
If URL should be determined per request, you may use HTTP trigger and read the URL from query parameters:
let url = req.query.myurl;
I'm not sure what exactly you are trying to achieve with parameterized timer-triggered function.
Another possibility is if your parameters are stored somewhere in e.g. Azure Document DB (Cosmos).
You could still use a TimerTrigger to invoke the function, and include a DocumentDB input binding allowing you to query for the specific parameter values needed to execute the function.
Here's a C# example triggered by Timer, with a DocumentDB input binding. Note: I'm using the latest VS2017 Preview tooling for Azure functions.
[FunctionName("TimerTriggerCSharp")]
public static void Run(
[TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, TraceWriter log,
[DocumentDB("test-db-dev", "TestingCollection", SqlQuery = "select * from c where c.doc = \"Test\"")] IEnumerable<dynamic> incomingDocuments)
{..}
With the following binding json:
{
"bindings": [
{
"name": "myTimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 */5 * * * *"
},
{
"type": "documentDB",
"name": "incomingDocuments",
"databaseName": "test-db-dev",
"collectionName": "TestingCollection",
"sqlQuery": "select * from c where c.docType = \"Test\"",
"connection": "my-testing_DOCUMENTDB",
"direction": "in"
}
],
"disabled": false
}