Azure / azure-functions-host

The host/runtime that powers Azure Functions
https://functions.azure.com
MIT License
1.92k stars 442 forks source link

RpcFunctionMetadata - script_file is empty in the request from host to java worker #8645

Open shreyas-gopalakrishna opened 2 years ago

shreyas-gopalakrishna commented 2 years ago

Investigative information

Exception observed in Functions logs

Microsoft.Azure.WebJobs.Script.Workers.Rpc.RpcException : Result: Failure
Exception: IllegalArgumentException: "" is not a qualified JAR file name
Stack: java.lang.IllegalArgumentException: "" is not a qualified JAR file name
at com.microsoft.azure.functions.worker.description.FunctionMethodDescriptor.guardAgainstUnqualifiedJarPath(FunctionMethodDescriptor.java:141)
at com.microsoft.azure.functions.worker.description.FunctionMethodDescriptor.validate(FunctionMethodDescriptor.java:106)
at com.microsoft.azure.functions.worker.broker.JavaFunctionBroker.loadMethod(JavaFunctionBroker.java:37)
at com.microsoft.azure.functions.worker.handler.FunctionLoadRequestHandler.execute(FunctionLoadRequestHandler.java:27)
at com.microsoft.azure.functions.worker.handler.FunctionLoadRequestHandler.execute(FunctionLoadRequestHandler.java:9)
at com.microsoft.azure.functions.worker.handler.MessageHandler.handle(MessageHandler.java:45)
at com.microsoft.azure.functions.worker.JavaWorkerClient$StreamingMessagePeer.lambda$onNext$0(JavaWorkerClient.java:92)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

This happens when RpcFunctionMetadata has empty script_file being passed to the Java worker.

IcM - https://portal.microsofticm.com/imp/v3/incidents/details/316217064/home

Please provide the following:

Repro steps

Provide the steps required to reproduce the problem: Do not know repro steps. Host to send empty script file can be a way to repro

Expected behavior

Jar location must be passed in the script_file and Java worker must execute the function

Actual behavior

Jar location passed is empty as the script_file is empty so the Java worker is not initialized correctly but host is sending further requests.

Host versions where this issue is seen 3.8.2.0 3.10.2.0 3.11.0.0 2.0.15229.0 3.7.1.0 3.12.0.0 3.12.1.

liliankasem commented 2 years ago

This probably needs some further looking into, but we get the script_file from the worker when we do a metadata request, and we handle the response here.

We set the value of script_file based on what we get, so if we didn't get this information during GetFunctionMetadata request, we set to empty:

ScriptFile = metadata.ScriptFile ?? string.Empty,

Can you confirm if the java worker is sending the correct information over in FunctionMetadataResponse? If it is, then there might be a bug somewhere potentially introduced during some of the refactoring for multi-language support cc: @soninaren

shreyas-gopalakrishna commented 2 years ago

The Java worker is currently not handling FunctionsMetadataRequest or FunctionMetadataResponse. I have added a work item in the Java worker for it. Any idea how this works without the FunctionsMetadataRequest?

brettsam commented 2 years ago

We'd get the value from the function.json. But there's some processing that occurs, for example: https://github.com/Azure/azure-functions-host/blob/dev/src/WebJobs.Script/Host/HostFunctionMetadataProvider.cs#L150.

So we need to try to narrow down where that could possibly be turning into an empty string, assuming the function.json is correct.

shreyas-gopalakrishna commented 2 years ago

Sharing the function.json here and here is the link for the Java app and the zip file being used.

{
  "scriptFile" : "../HttpTrigger-1.0-SNAPSHOT.jar",
  "entryPoint" : "com.function.Function.run",
  "bindings" : [ {
    "type" : "httpTrigger",
    "direction" : "in",
    "name" : "req",
    "methods" : [ "GET", "POST" ],
    "authLevel" : "FUNCTION"
  }, {
    "type" : "http",
    "direction" : "out",
    "name" : "$return"
  } ]
}