Durable Functions - infinite execution with state doesn't work - azure

I'm setting up a durable Function that should run infinitely with by invoking itself every hour and keeping a state. The function compiles, bus fails at run with the following error:
2017-07-12T07:04:05.614 Exception while executing function: Functions.DurableTimer.
Microsoft.Azure.WebJobs.Host: Exception binding parameter 'context'.
Microsoft.Azure.WebJobs.Extensions.DurableTask: Cannot convert to DurableOrchestrationContext.
Function code
#r "Microsoft.Azure.WebJobs.Extensions.DurableTask"
using System;
using System.Threading;
public static async Task Run(DurableOrchestrationContext context, TraceWriter log)
{
log.Info($"Durable function executed at: {context.CurrentUtcDateTime}");
// sleep for one hour between calls
DateTime nextExecution = context.CurrentUtcDateTime.AddHours(1);
await context.CreateTimer(nextExecution, CancellationToken.None);
int counterState = context.GetInput<int>();
log.Info($"Counter state: {counterState}");
counterState++;
context.ContinueAsNew(counterState);
}
function.json
{
"bindings": [
{
"name": "context",
"type": "orchestrationTrigger",
"direction": "in"
}
],
"disabled": false
}

My guess is that you are trying to manually trigger the orchestration function in the portal UI, which unfortunately is not supported at this time. I verified by trying to reproduce your exact scenario and clicking the Run button in the portal. I've opened a bug to track this issue: https://github.com/Azure/azure-functions-durable-extension/issues/10
Assuming that's the case, you can workaround it by creating a separate function which knows how to trigger your orchestrator function. Here is the example I posted in the GitHub issue:
Code
#r "Microsoft.Azure.WebJobs.Extensions.DurableTask"
using System;
public static async Task Run(string functionName, DurableOrchestrationClient starter, TraceWriter log)
{
log.Info($"Starting orchestration named: {functionName}");
string instanceId = await starter.StartNewAsync(functionName, null);
log.Info($"Started orchestration with ID = '{instanceId}'.");
}
function.json
{
"bindings": [
{
"type": "manualTrigger",
"direction": "in",
"name": "functionName"
},
{
"name": "starter",
"type": "orchestrationClient",
"direction": "in"
}
],
"disabled": false
}
This is a generic function that can start any orchestrator function by name. In your case, you can put DurableTimer as the input.
Apologies that this is non-obvious and thanks for your patience as we smooth out the experience. :)

Related

Azure function trigger go to error when start

I'm trying to implement the example of 'Image Resizer' that I find here:
https://github.com/jefking/fl-image-resize
when I start the function it returns me this error
Exception while executing function: Functions.ImageTriggerCSharp01. Microsoft.Azure.WebJobs.Host: Exception binding parameter 'myBlob'. Microsoft.WindowsAzure.Storage: The remote server returned an error: (404) Not Found.
subsequently the function is activated every minute without errors. Then, when I load a file, this error is generated:
Function compilation error
error: Missing a trigger argument named 'myBlob'.
warning: Missing binding argument named 'outputBlob'. Mismatched binding argument names may lead to function indexing errors.
what's wrong?
*********UPGRADE***********
i have this code:
run.csx=
#r "System.Drawing"
using System;
using System.Drawing;
using ImageProcessor;
private static readonly Size size = new Size(EnvAsInt("ImageResize-Width"), EnvAsInt("ImageResize-Height"));
public static void Run(Stream myBlob, Stream outputBlob, string name, TraceWriter log)
{
log.Info($"C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
if (myBlob==null){
log.Info($"C# myBlob is NULL");
}
log.Info($"C# ok2");
if (outputBlob==null){
log.Info($"C# outputBlob is NULL");
}
log.Info($"C# ok3");
using (var imageFactory = new ImageFactory())
{
log.Info($"C# ok31");
imageFactory
.Load(myBlob)
.Resize(size)
.Save(outputBlob);
}
log.Info($"C# ok4");
}
private static int EnvAsInt(string name) => int.Parse(Env(name));
private static string Env(string name) => System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
enter code here
function.json=
{
"bindings": [
{
"type": "blob",
"name": "outputBlob",
"path": "photosthumbnails/{name}",
"connection": "AzureWebJobsStorage",
"direction": "out"
},
{
"type": "blobTrigger",
"name": "myBlob",
"path": "photos/{name}",
"connection": "AzureWebJobsStorage",
"direction": "in"
}
],
"disabled": false
}
i have the error in
imageFactory
.Load(myBlob)
.Resize(size)
.Save(outputBlob);
what can i do?
ok. i resolve.
the error is on
private static readonly Size size = new Size(EnvAsInt("ImageResize-Width"), EnvAsInt("ImageResize-Height"));
the two properties, ImageResize-Width and ImageResize-Height, were not included in the 'function' settings.
It's my first Azure function ... ^_^
Do verify the parameter names in run.csx and in the function.json file. The parameter names passed in the run.csx file should match with function.json file. Do check them in the reference you provided.

Defining a return for a very simple manual Azure function

I have an Azure function that does this:
public static int Run(int myvalue, TraceWriter log)
{
log.Info($"C# manually triggered function called with input: {myvalue}");
if (myvalue == 1) return 1;
return (myvalue + 1);
}
I created it directly in the portal; however, my attempt at the bindings are probably wrong:
{
"bindings": [
{
"type": "manualTrigger",
"direction": "in",
"name": "myvalue"
},
{
"type": "int",
"direction": "out",
"name": "$return"
}
],
"disabled": false
}
When I run it inside the portal, it gives me a 202 (accepted), but doesn't output the return value from the function.
My question is, basically, why am I not getting any output; however, I suppose my first question should be (is), should I be getting output; and if so, what's wrong with my binding?
This is a simplified version of a slightly more complex function, that I intend to use as a condition inside a logic app (hence why I need a return value).
int is not a supported type for manual trigger. You should be seeing an error like this in the logs:
[Error] Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.ManualTriggerCSharp1'. Microsoft.Azure.WebJobs.Script: Can't bind ManualTriggerAttribute to type 'System.Int32'.
If you change the parameter type to string, logging should work:
public static void Run(string myvalue, TraceWriter log)
{
log.Info($"C# manually triggered function called with input: {myvalue}");
}
Now, there is no point in returning anything from manual trigger. You can keep returning an int but it will be ignored. But remove the second binding:
{
"bindings": [
{
"type": "manualTrigger",
"direction": "in",
"name": "myvalue"
}
],
"disabled": false
}
To return a value, you probably need to switch to HTTP trigger, read the data from HTTP request and return HTTP response.

How to make Azure Function triggered by Azure Event Grid with a binding to Blob Storage [duplicate]

This question already has an answer here:
Azure Function blob binding
(1 answer)
Closed 5 years ago.
Trying to remake the Azure Grid Image Resize example in c# using visual studio but having issues making the azure function trigger be triggered by the event grid and bind to the blob storage.
Current Code:
using Microsoft.Azure.WebJobs.Extensions.EventGrid;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Azure.WebJobs;
using Microsoft.WindowsAzure.Storage.Blob;
namespace FunctionApp
{
public static class CreateIndex
{
[FunctionName("CreateIndex")]
[StorageAccount("backup_STORAGE")]
public static void Run(
[EventGridTrigger()] EventGridEvent myEvent,
[Blob("{data.url}")] CloudBlockBlob inputBlob,
TraceWriter log)
{
log.Info(myEvent.ToString());
log.Info(inputBlob.ToString());
}
}
}
Generated function.json:
{
"generatedBy": "Microsoft.NET.Sdk.Functions.Generator-1.0.6",
"configurationSource": "attributes",
"bindings": [
{
"type": "eventGridTrigger",
"name": "myEvent"
}
],
"disabled": false,
"scriptFile": "../bin/FunctionApp.dll",
"entryPoint": "FunctionApp.CreateIndex.Run"
}
The binding is working for the event grid trigger but not the Blob input.
Expected function.json:
{
"bindings": [
{
"type": "EventGridTrigger",
"name": "myEvent",
"direction": "in"
},
{
"type": "blob",
"name": "inputBlob",
"path": "{data.url}",
"connection": "myblobstorage_STORAGE",
"direction": "in"
}
],
"disabled": false
}
Precompiled functions generate function.json for you, but they only put trigger binding inside of it. It's OK that your blob binding is not in this file.
The input Blob binding will still work: runtime will pick it up based on your attributes.

Azure Functions - ICollector binding not in resulting function.json

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.

How do you reference a blob from an Azure Timer Trigger Function?

I have an Azure Timer Trigger Function that should do some calculations and write the results to a json file in a pre-existing blob. How do I reference the pre-existing blob from within the Timer Triggered function?
I can't seem to find any documentation that provides a code sample. Can someone provide one?
First, you need to update your function.json configuration file, to bind the blob to the CloudBlockBlob instance you'll be using in your .csx code. You can edit it in Azure Portal via the "Integrate" option (the one with the lighting icon) under your function, in the Function Apps menu. On the top right of that page is a link that reads "Advanced Editor". Clicking that link will take you to your funciton's function.json file:
You'll see a JSON array named "bindings" that contains a JSON object that configures your timer. You'll want to add another JSON object to that array to bind your blob to a CloudBlockBlob instance that you'll be referencing in your function. Your function.json file will look something like this:
{
"bindings": [
{
"name": "myTimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 */5 * * * *"
},
{
"type": "blob",
"name": "myBlob",
"path": "your-container-name/your_blob_filename.json",
"connection": "AzureWebJobsStorage",
"direction": "inout"
}
],
"disabled": false
}
Now you just need to update your function's Run method's signature. It looks like this by default:
public static void Run(TimerInfo myTimer, TraceWriter log)
Add your blob variable to the end of that signature (and also add the necessary includes):
#r "Microsoft.WindowsAzure.Storage"
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
public static void Run(TimerInfo myTimer, TraceWriter log, CloudBlockBlob myBlob)
And you're all set! "myBlob" is bound to the blob "your_blob_filename.json" in your "your-container-name" container.

Resources