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)
.NET CORE Install from ↓. https://www.microsoft.com/net/learn/get-started/windows node.js
Select "Windows Installer (.msi)". https://nodejs.org/en/download/
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 azure-functions-core-tools@core
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
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
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>
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'
I will finally deploy it.
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": "xxxx@xxxxxxxxxxxxxxxxxxxxxx",
"type": "user"
}
}
]
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".
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!
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);
}
}
}
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.
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.
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!
I'd like to try various things, but for the time being, that's it.
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.
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