4
votes

Background

Java Azure functions 2, using blob storage with event grid subsription for blob create events which the function (see below) is bound to via the event trigger.

Problem

Not clear how to bind a blob (See @BlobInput Java annotation) Input Blob Binding from Azure functions which the documentation illudes to, but not sure if possible in the Java API, unlike its C# counterpart.

When the function is invocked nothing is bound to the content varaible using the @BlobInput annotation, so once the line is reached where the content variable is reached, it results in a null pointer.

The path = "{data.url}" based on documentation allows you to access event data passed to the function. The data passed from the event is all bound to the EventSchema event POJO also (see below for an example of an event).

The @StorageAccount("AzureWebJobsStorage") links to the properties stored and setup by default via the functions configuration, which is correct.

Tried

Deployed azure function:

@StorageAccount("AzureWebJobsStorage")
@FunctionName("myfunc")
public void run(@EventGridTrigger(name = "blobeventgrid") EventSchema event,
                @BlobInput(name = "zipfile",dataType = "binary",path = "{data.url}") byte[] content,
                final ExecutionContext context) {
    context.getLogger().info("Java Event Grid trigger function executed.");
    context.getLogger().info("Id: " + event.id);
    context.getLogger().info("Data: " + event.data);
    context.getLogger().info("zip file: " + content.length);
}

Example Event Grid Event

{
  "topic": "/subscriptions/<omitted>/resourceGroups/java-functions-group/providers/Microsoft.Storage/storageAccounts/<omitted storageaccount>",
  "subject": "/blobServices/default/containers/mycontainer/blobs/compressed.zip",
  "eventType": "Microsoft.Storage.BlobCreated",
  "eventTime": "2019-10-02T12:46:33.2915427Z",
  "id": "<omitted>",
  "data": {
  "api": "PutBlob",
  "clientRequestId": "<omitted>",
  "requestId": "<omitted>",
  "eTag": "<omitted>",
  "contentType": "application/zip",
  "contentLength": 32460,
  "blobType": "BlockBlob",
  "url": "https://<omitted storageaccount>.blob.core.windows.net/mycontainer/compressed.zip",
  "sequencer": "<omitted>",
  "storageDiagnostics": {
  "batchId": "<omitted>"
    }
  },
  "dataVersion": "",
  "metadataVersion": "1"
}

Log from running function locally (remote is same)

[10/05/2019 18:48:16] Executing HTTP request: {
[10/05/2019 18:48:16]   "requestId": "299a3870-98cf-41cf-b418-7cdb33c1f1c7",
[10/05/2019 18:48:16]   "method": "POST",
[10/05/2019 18:48:16]   "uri": "/runtime/webhooks/EventGrid"
[10/05/2019 18:48:16] }
[10/05/2019 18:48:17] Executing 'Functions.myFunc' (Reason='EventGrid trigger fired at 2019-10-05T19:48:17.4343990+01:00', Id=82a2f47b-34bc-492f-8b60-12601beb45ee)
[10/05/2019 18:48:18] Java Event Grid trigger function executed.
[10/05/2019 18:48:18] Event content 
[10/05/2019 18:48:18] Subject: /blobServices/default/containers/mycontainer/blobs/zip/compressed.zip
[10/05/2019 18:48:18] Time: Mon Sep 30 20:46:33 BST 2019
[10/05/2019 18:48:18] Id: 7de5edc4-c01e-0107-1bc7-77755f061e49
[10/05/2019 18:48:18] Data: {api=PutBlob, clientRequestId=007dd554-e3bb-11e9-80b4-dca90473b192, requestId=7de5edc4-c01e-0107-1bc7-77755f000000, eTag=0x8D745DEE5936EE3, contentType=application/zip, contentLength=32460.0, blobType=BlockBlob, url=https://<ommitted storage account>.blob.core.windows.net/mycontainer/zip/compressed.zip, sequencer=000000000000000000000000000007E200000000002ab872, storageDiagnostics={batchId=1c15a3b6-2006-0046-00c7-771b19000000}}
[10/05/2019 18:48:18] Executed 'Functions.myFunc' (Failed, Id=82a2f47b-34bc-492f-8b60-12601beb45ee)
[10/05/2019 18:48:18] System.Private.CoreLib: Exception while executing function: Functions.myFunc. System.Private.CoreLib: Result: Failure
[10/05/2019 18:48:18] Exception: NullPointerException: 

Falls over because of nothing is bound to content byte[]...

Alternative

Using the Azure Java SDK, but trying to stay with the semantics around Azure functions.

1
Is your StorageAccount("AzureWebJobsStorage") the same as <omitted storageaccount>? If it is not, use the connection in the @BlobInput. Btw. using the C# is working well.Roman Kiss
Updated the post to address your querry, thanksRST
for test purpose: add the line: context.getLogger().info("Url: " + event.data.url);Roman Kiss
The event works, that's not my question, I can access anything in the event object... The question is around the Blob InputRST
So, you can see the url address in this added line, are you? I am using a C#, that's why I have these troubleshooting questions, otherwise I will do it in my environment. One more troubleshooting question: try to replace binding with an explicitly value of the data.url from the event object to proof the BlobInput binding.Roman Kiss

1 Answers

3
votes

Your function is almost correct. Based on my test, the value of {data.url} would be a http url like the following:

https://storagetest789.blob.core.windows.net/test/test.txt

And if you set the correct storage connection string, the binding will work and you will get the content.

Here is my verification:

1. Code

public class Function {

    @FunctionName("StroageEventGrid")
    @StorageAccount("AzureWebJobsStorage")
    public void run(@EventGridTrigger(name = "blobeventgrid") EventSchema event, 
                    @BlobInput(name = "blob",dataType = "binary",path = "{data.url}") byte[] content,
                    final ExecutionContext context) 
    {
        context.getLogger().info((String)event.data.get("url"));
        if(content != null)
            context.getLogger().info("Length: " + content.length);
        else
            context.getLogger().info("Content is null");
    }
}

public class EventSchema {

  public String topic;
  public String subject;
  public String eventType;
  public Date eventTime;
  public String id;
  public String dataVersion;
  public String metadataVersion;
  public Map<String, Object> data;

}

2. Check the AzureWebJobsStorage connectiong string in application settings

enter image description here

Make sure that it is the correct connection string of your target storage account.

3. Upload a new blob

enter image description here

You can see that I get the right result.

So, I suggest you check your connection string setting. By default, your local test settings will not update to the cloud, which may causes this issue.