Debugging Java Language Worker on Azure Functions
Tags: azure, serverless, java
Published: 2020-08-15 07:47:31

If you want to contribute Java Language worker, how to debug it? It works with [Azure Functions Host](https://github.com/Azure/azure-functions-host).

There is three player for this debug story. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9ey4izqh0r6ed2drf6yo.jpg)

# Architecture

## 1. Azure Functions Host (C#)
The main process of the [Azure Functions](https://github.com/Azure/azure-functions-host) execution. Under the food, it uses [WebJobsSDK](https://github.com/Azure/azure-webjobs-sdk). 

## 2. Binding Extensions (C# + wrapper)
Azure functions has a several [Triggers and bindings](https://docs.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings). It will receive an event by the various measure. `Http`, `Queue`, `Kafka`, `EventHubs`, `CosmosDB` ... and so on. It also outputs messages. It is written by C#. Language implementation is an wrapper of the C# implementation. 

## 3. Java Language Worker (Java)
[Java Language Worker](https://github.com/Azure/azure-functions-java-worker) is a worker process. Except for C# precompile implementation, Azure Functions host delegate the function execution to each language workers via gRPC. 

## 4. Azure Functions Java Library (Java)
That is mainly the definition of annotation that is used by the Binding Extensions wrapper. The library is referenced by User's Azure Functions, Java Language Worker, and [Azure Functions Maven Plugin](https://github.com/microsoft/azure-maven-plugins).

## 5. Application Insights Agent (Java)
It is injected with the Java Language Worker as an [agent](https://www.developer.com/java/data/what-is-java-agent.html). It is automatically track the telemetries with correlation without changing any code. The automated dependency tracking is limited for some libraries. Please refer to it on this article. 

* [Java codeless application monitoring Azure Monitor Application Insights - public preview](https://docs.microsoft.com/en-us/azure/azure-monitor/app/java-in-process-agent)

## 6. Azure Functions (Java)
Azure Functions that customers write. The Language worker class loader load the functions by the annotations.

# How to debug it? 
Since there is a lot of players, how can I debug the Java Worker part? We can easily debug the Azure Functions part. However, Java Worker is started by the Azure Functions Host. 

## Create an Azure Functions
For debugging the Java Language Worker, we need create a function to execute it. Please refer to [Quickstart: Create a function in Azure that responds to HTTP requests](https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function-azure-cli?tabs=bash%2Cbrowser&pivots=programming-language-java)

One point for the debugging is, how to manage the `Binding extensions`. Usually, we use [Extension bundles](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-register#extension-bundles). So we don't need to install the Bindings by setting the `host.json`. It will automatically install the extensions.

```json
{
    "version": "2.0",
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[1.*, 2.0.0)"
    }
}
```
However, the local debug scenario, you might need to install the extension by your self.  You need to have `extension.csproj` file under the, `target/azure-functions/<YOUR_FUNCTION_APP_NAME>` directory.

### Install extension

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dc71dt0tvc9qvjfg4ra3.png)

This code is a sample for `EventHubs`

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
	<WarningsAsErrors></WarningsAsErrors>
	<DefaultItemExcludes>**</DefaultItemExcludes>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.EventHubs" Version="4.1.1" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.1.7" />
  </ItemGroup>
</Project>
```

Then go to the `target/azure-functions/<FUNCTION_APP_NAME>` dir. 

```powershell
PS > mvn clean package
PS > cp extension.csproj target\azure-functions\fabrikam-functions
PS > cd target\azure-functions\fabrikam-functions
PS > func extension install
```

You will see the `bin` directory that contains `DLL` files for the extensions. The DLL is libraries of the Extension. 

Now ready to configure Azure Functions Host. 

## Configure Azure Functions Host for Java Worker Debugging

### WebJobs.Script.WebHost as startup
Clone the [Azure Functions Host](https://github.com/Azure/azure-functions-host). Then open Visual Studio and make `WebJobs.Script.WebHost` as startup project. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/9cy5h5md4v5xvpy0fz0g.png)

### Configure Environment Variables
Right click `WebJobs.Script.WebHost` > `Properties` > Debug. Configure the environment variables.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fieaytmcbo86ql97qvwx.png)

| Name | Value (sample) | Description |
| ---- | ----- | ----------- |
| AzureWebJobsScriptRoot | C:\Users\tsushi\Code\java\azure-functions-samples\EventHubs\target\azure-functions\fabrikam-functions-20200814172147278 | Point to the azure functions function app directory |
| ASPNETCORE_ENVIRONMENT | Development | Mode for AspNetCore |
| AZURE_FUNCTIONS_ENVIRONMENT | Development | Mode for Azure Functions Host|
| AzureWebJobsDashboard | UseDevelopmentStorage=true | Connection string of Storage Account or Storage Emulator for the functions host dashboard.| 
| AzureWebJobsStorage | UseDevelopmentStorage=true | Connection string of Storage Account or Storage Emulator for the functions host.|
|  FUNCTIONS_WORKER_RUNTIME | java | Worker Runtime |
| languageWorkers:java:arguments | -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 | Environment Variables for debugging |

Also you need to add **AppSettings that your functions need**. 
You might wondering why `AZURE_FUNCTIONS_ENVIRONMENT` and `ASPNETCORE_ENVIRONMENT`. 

> You'll want to use `AZURE_FUNCTIONS_ENVIRONMENT`. The Functions runtime that powers a Function app on Azure is the WebHost project in this repo. As the host is initializing, it looks for the `AZURE_FUNCTIONS_ENVIRONMENT` app setting (as `EnvironmentSettingNames.EnvironmentNameKey`) and [passes it to the IWebHostBuilder](https://github.com/Azure/azure-functions-host/blob/bb15fba262572a9af1aff7f57edfaeb0f9f9b9de/src/WebJobs.Script.WebHost/Program.cs#L43). Using only `ASPNETCORE_ENVIRONMENT` can lead to desired behavior changes and telemetry being missed.

### Update JavaWorker

If you modify your code on the Java worker, you need to build it and package it on the Java Worker's cloned repo.

```powershell
PS > mvn clean package
```

You will find `azure-functions-java-worker-<VERSION>.jar`. Copy the jar file to the `WebJobs.Script.WebHost\bin\Debug\netcoreapp3.1\workers\java` on the Azure Functions Host project. 

Now ready to debug. hit `F5`. Then debugging starts. One tips is, if you choose `IIS Express` you can not see a log. Choose 1WebJobs.Script.WebHost` instead. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fxkcdu3t2cwvu82c10tp.png)

### Attach from an IntelliJ

Follow [Debugging Azure Functions Host and Java Worker](https://github.com/Azure/azure-functions-java-worker/wiki/Debugging-Azure-Functions-Host-and-Java-Worker)

Create a remote debugging. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kf99hh3jnhxh8da214fi.png)

Just click start the debugging on the IntelliJ. It attach to the `5005` port that is the Java worker. Just send an request `http://localhost:5000/api/YOUR_FUNCTIONS_NAME`. or sending queues for triggering your Azure Functions. 

It works!
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jcranhq6s6sxp4veewco.png)

# Resource
* [Contributor Onboarding](https://github.com/Azure/azure-functions-host/wiki/Contributor-Onboarding)
* [Debugging Azure Functions Host and Java Worker](https://github.com/Azure/azure-functions-java-worker/wiki/Debugging-Azure-Functions-Host-and-Java-Worker)