Azure functions in java

Overview

It seems that java is officially supported by azure functions, so let's try it for a while. Basically, it was done according to the following flow, but I stumbled several times on the way, so make a note including the contents of the stumbling. Create your first function using Java and Maven (preview)

environment

First of all, various installations

.NET CORE Install from ↓. https://www.microsoft.com/net/learn/get-started/windows node.js

installer

Select "Windows Installer (.msi)". https://nodejs.org/en/download/

Verification

After installing, the path is already in place. Let's check at the command prompt.

> node -v
v8.9.4

Azure Functions Core Tools A tool that allows you to run and debug Azure functions locally. Now that you have node.js installed, install it using npm.

>npm install -g [email protected]
C:\Users\xxx\AppData\Roaming\npm\func -> C:\Users\xxx\AppData\Roaming\npm\node_modules\azure-functions-core-tools\lib\main.js
C:\Users\xxx\AppData\Roaming\npm\azurefunctions -> C:\Users\xxx\AppData\Roaming\npm\node_modules\azure-functions-core-tools\lib\main.js
C:\Users\xxx\AppData\Roaming\npm\azfun -> C:\Users\xxx\AppData\Roaming\npm\node_modules\azure-functions-core-tools\lib\main.js

[email protected] postinstall C:\Users\xxx\AppData\Roaming\npm\node_modules\azure-functions-core-tools
node lib/install.js

[==================] Downloading Azure Functions Cli
+ [email protected]
added 46 packages in 8.164s

Azure CLI As the name suggests, it is a tool that allows you to use Azure on the command line. Install by referring to the following. https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli-windows

Create a project

Move to the workspace of eclipse at the command prompt and execute the following command. I think you can create a new project with GUI.

mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype

You will be asked for various groupIds, so give it a name you like.

Define value for property 'groupId': jp.suzuq
Define value for property 'artifactId': azure.functions
Define value for property 'version' 1.0-SNAPSHOT: : 0.0.1
Define value for property 'package' jp.suzuq: : jp.suzuq.azure.functions
Define value for property 'appName' azure.functions-20180222185249620: :
Define value for property 'appRegion' westus: : jp

Build immediately

When the project is completed, a simple function class is created. First, let's build and deploy this and check the operation.

mvn clean package

If I did it as it was, the build failed with the following error.

Failed to execute goal com.microsoft.azure:azure-functions-maven-plugin:0.1.10:package (package-functions) on project azure.functions: Execution package-functions of goal com.microsoft.azure:azure-functions-maven-plugin:0.1.10:package failed: A required class was missing while executing com.microsoft.azure:azure-functions-maven-plugin:0.1.10: package: com/microsoft/azure/serverless/functions/annotation/DocumentDBInput

It seems that azure-functions-maven-plugin is something wrong, so I changed the version to the latest 0.2.1 and it worked.

pom.xml


                <plugin>
                    <groupId>com.microsoft.azure</groupId>
                    <artifactId>azure-functions-maven-plugin</artifactId>
                    <version>0.2.1</version>
                </plugin>

Test run locally

Before deploying to Azure, try running it locally.

mvn azure-functions:run

The functions logo is displayed on the console ...

[INFO] Starting running Azure Functions...

                  %%%%%%
                 %%%%%%
            @   %%%%%%    @
          @@   %%%%%%      @@
       @@@    %%%%%%%%%%%    @@@
     @@      %%%%%%%%%%        @@
       @@         %%%%       @@
         @@      %%%       @@
           @@    %%      @@
                %%
                %

When the following message appears, you are ready to go.

Http Functions:

	hello: http://localhost:7071/api/hello

As instructed, try doing the following in curl: If you don't have curl, use a tool that can throw something http.

curl -w '\n' -d hoge http://localhost:7071/api/hello

You can see that the log is output to the console and it is running.

[2018/05/02 9:51:28] Function started (Id=0aed5288-e5ff-47e2-868b-8455d7731b70)
[2018/05/02 9:51:28] Executing 'Functions.hello' (Reason='This function was programmatically called via the host APIs.', Id=0aed5288-e5ff-47e2-868b-8455d7731b70)
[2018/05/02 9:51:28] Java HTTP trigger processed a request.
[2018/05/02 9:51:28] Function "hello" (ID: 40832889-9057-4664-885e-c84407660a4a) invoked by Java Worker
[2018/05/02 9:51:28] Function completed (Success, Id=0aed5288-e5ff-47e2-868b-8455d7731b70, Duration=5ms)
[2018/05/02 9:51:28] Executed 'Functions.hello' (Succeeded, Id=0aed5288-e5ff-47e2-868b-8455d7731b70)

The execution result was returned with the 200th response.

Hello, hoge'

Deploy

I will finally deploy it.

Login to azure

Log in using the azure CLI. Open powershell on your PC and "az login".

> az login
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.

As instructed, go to https://microsoft.com/devicelogin and enter the code displayed in the powershell console. The "az login" command exits and shows the information about the logged in azure.

[
  {
    "cloudName": "AzureCloud",
    "id": "xxxxxxxxxxxxxxxxxxxxxxx",
    "isDefault": true,
    "name": "Microsoft Azure",
    "state": "Enabled",
    "tenantId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "user": {
      "name": "[email protected]",
      "type": "user"
    }
  }
]

Deploy with maven

Go back to eclipse and execute the following maven command.

mvn azure-functions:deploy

I got an error ...

[ERROR] Failed to execute goal com.microsoft.azure:azure-functions-maven-plugin:0.2.1:deploy (default-cli) on project azure.functions: Status code 400, {"error":{"code":"LocationNotAvailableForResourceGroup","message":"The provided location 'jp' is not available for resource group. List of available regions is 'centralus,eastasia,southeastasia,eastus,eastus2,westus,westus2,northcentralus,southcentralus,westcentralus,northeurope,westeurope,japaneast,japanwest,brazilsouth,australiasoutheast,australiaeast,westindia,southindia,centralindia,canadacentral,canadaeast,uksouth,ukwest,koreacentral,koreasouth,francecentral'."}}

Since region says this, try changing the region-like setting of pom.xml from "jp" to "japaneast".

pom.xml


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <functionAppName>azure.functions-9999999.azurewebsites.net</functionAppName>
        <functionAppRegion>japaneast</functionAppRegion>
    </properties>

This time I got a different error.

[ERROR] Failed to execute goal com.microsoft.azure:azure-functions-maven-plugin:0.2.1:deploy (default-cli) on project azure.functions: The host name azure.functions-20180222185249620.azurewebsites.net is invalid. OnError while emitting onNext value: retrofit2.Response.class

Try changing the function name. The function name will also be the file name of the jar deployed in azure, so build it again here.

pom.xml


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <functionAppName>testFunction</functionAppName>
        <functionAppRegion>japaneast</functionAppRegion>
    </properties>

Also an error.

[ERROR] Failed to execute goal com.microsoft.azure:azure-functions-maven-plugin:0.2.1:deploy (default-cli) on project azure.functions: {
[ERROR] "message": "An error has occurred.",
[ERROR] "exceptionMessage": "An error occurred when trying to create a controller of type 'DeploymentController'. Make sure that the controller has a parameterless public constructor.",
[ERROR] "exceptionType": "System.InvalidOperationException",
[ERROR] "stackTrace": "   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
[ERROR] "innerException": {
[ERROR] "message": "An error has occurred.",
[ERROR] "exceptionMessage": "The user name or password is incorrect.\r\n",
[ERROR] "exceptionType": "System.IO.IOException",
[ERROR] "stackTrace": "   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)\r\n   at System.IO.Directory.InternalCreateDirectory(String fullPath, String path, Object dirSecurityObj, Boolean checkHost)\r\n   at System.IO.Directory.InternalCreateDirectoryHelper(String path, Boolean checkHost)\r\n   at System.IO.Directory.CreateDirectory(String path)\r\n   at System.IO.Abstractions.DirectoryWrapper.CreateDirectory(String path)\r\n   at Microsoft.Web.Deployment.WebApi.PathHelper.GetLogFilesFolderPath(IEnvironment environment)\r\n   at Microsoft.Web.Deployment.WebApi.DeploymentController..ctor()\r\n   at lambda_method(Closure )\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
[ERROR] }
[ERROR] }: OnError while emitting onNext value: retrofit2.Response.class

I don't know what you're saying, so I tried it again and for some reason SUCCESS.

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 35.832 s
[INFO] Finished at: 2018-05-10T18:55:38+09:00
[INFO] Final Memory: 48M/551M
[INFO] ------------------------------------------------------------------------

Let's check the function deployed in the azure portal. From the side menu "Function App".

azurePortal.png

Try to run

You can copy the URL from "Getting the URL of the function" in the upper right of the image above. Let's make a request from curl to the copied URL.

curl -w '\n' https://functionName.azurewebsites.net/api/hello -d AzureFunctions
Hello, AzureFunctions

It worked!

Make an original function

For the time being, the function prepared by default worked, so let's make an original one. I just ran this program that was automatically generated in the workspace. With this as a reference, I will create my own function.

Function.java


package jp.suzuq.azure.functions;

import java.util.*;
import com.microsoft.azure.serverless.functions.annotation.*;
import com.microsoft.azure.serverless.functions.*;

/**
 * Azure Functions with HTTP Trigger.
 */
public class Function {
    /**
     * This function listens at endpoint "/api/hello". Two ways to invoke it using "curl" command in bash:
     * 1. curl -d "HTTP Body" {your host}/api/hello
     * 2. curl {your host}/api/hello?name=HTTP%20Query
     */
    @FunctionName("hello")
    public HttpResponseMessage<String> hello(
            @HttpTrigger(name = "req", methods = {"get", "post"}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");

        // Parse query parameter
        String query = request.getQueryParameters().get("name");
        String name = request.getBody().orElse(query);

        if (name == null) {
            return request.createResponse(400, "Please pass a name on the query string or in the request body");
        } else {
            return request.createResponse(200, "Hello, " + name);
        }
    }
}

Make a timer trigger

The default is a function that is triggered by an http request, so let's create a function that is triggered by a timer.

TimerFunction.java


package jp.suzuq.azure.functions;

import com.microsoft.azure.serverless.functions.ExecutionContext;
import com.microsoft.azure.serverless.functions.annotation.FunctionName;
import com.microsoft.azure.serverless.functions.annotation.TimerTrigger;

public class TimerFunction {
    @FunctionName("timer")
    public void timer(
            @TimerTrigger(name = "timer", schedule = "0 */5 * * * *") String timerInfo,
            final ExecutionContext context) 
    {
        context.getLogger().info("timerInfo : " + timerInfo);

    }
}

Annotate the first argument of the method with @TimerTrigger. Then, describe the schedule in cron format in "schedule". This is the function execution schedule.

Add library

I wanted to make Azure functions with java, because I wanted to use various libraries of java. There are a lot of useful java classes in the in-house maven repository, and I use them in my daily development, so I thought it would be nice if I could use them in Azure functions as well.

Let's add it to pom.xml and deploy it.

pom.xml


		<dependency>
			<groupId>jp.hoge</groupId>
			<artifactId>HogeCommon</artifactId>
			<version>1.20.0</version>
		</dependency>

When I try to move it, the function times out for some reason, and it is forcibly terminated in the middle. I was wondering why it timed out, but after all, it seems that the library I added to pom was not included in the pre-built module. Then throw a ClassNotFoundException ...

Pre-built modules can be downloaded in Kudu from the Azure portal if you want to see the target folder in the eclipse workspace or what was actually deployed.

スケッチ.png

スケッチ2.png

Since the build method was bad, I modified pom.xml by referring to the following. How to add dependency JAR in java azure functions

pom.xml


			<plugin>
			   <groupId>org.apache.maven.plugins</groupId>
			   <artifactId>maven-assembly-plugin</artifactId>
			   <configuration>
			      <appendAssemblyId>false</appendAssemblyId>
			      <descriptorRefs>
			         <descriptorRef>jar-with-dependencies</descriptorRef>
			      </descriptorRefs>
			      <archive />
			   </configuration>
			   <executions>
			      <execution>
			         <id>make-assembly</id>
			         <phase>package</phase>
			         <goals>
			            <goal>single</goal>
			         </goals>
			      </execution>
			   </executions>
			</plugin>

Wow! It worked! 1528452015300.png

I'd like to try various things, but for the time being, that's it.

Impressions

I am happy to be able to use the in-house library with Azure Functions. But after all it is troublesome to prepare various things. If it's a simple function, it's easiest to make it with javascript. It's nice that java can reuse existing assets in the company like this time and debug locally. I would like to use it properly according to the purpose.

Helpful site

Create your first function using Java and Maven (preview) Set trigger in java Azure CLI installation & login (Windows version) How to add dependency JAR in java azure functions

Recommended Posts

Azure functions in java
Create Azure Functions in Java
I dealt with Azure Functions not working in Java
Run Java application in Azure Batch
Partization in Java
Changes in Java 11
Rock-paper-scissors in Java
Pi in Java
FizzBuzz in Java
[java] sort in list
Read JSON in Java
Interpreter implementation in Java
Rock-paper-scissors app in Java
Constraint programming in Java
Put java8 in centos7
NVL-ish guy in Java
Combine arrays in Java
"Hello World" in Java
Callable Interface in Java
Comments in Java source
Format XML in Java
Simple htmlspecialchars in Java
Boyer-Moore implementation in Java
Hello World in Java
Use OpenCV in Java
webApi memorandum in java
Type determination in Java
Ping commands in Java
Various threads in java
Heapsort implementation (in java)
Zabbix API in Java
ASCII art in Java
Compare Lists in Java
POST JSON in Java
Express failure in Java
Create JSON in Java
Date manipulation in Java 8
What's new in Java 8
Use PreparedStatement in Java
What's new in Java 9,10,11
Parallel execution in Java
Initializing HashMap in Java
How to call functions in bulk with Java reflection
Delete All from Java SDK in Azure Cosmos DB
Change Java heap size in Tomcat in Azure App Service
Android-Upload image files to Azure Blob Storage in Java
Remote debugging of Java applications in Azure Web Apps
Read binary files in Java 1
Avoid Yubaba's error in Java
[Neta] Sleep Sort in Java
Edit ini in Java: ini4j
Java history in this world
Let Java segfault in 6 lines
Try calling JavaScript in Java
Try developing Spresense in Java (1)
I made roulette in Java.
Create hyperlinks in Java PowerPoint
Implement two-step verification in Java
Refactoring: Make Blackjack in Java
Write flyway callbacks in Java
Topic Analysis (LDA) in Java