Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Discussion] Azure Functions Runtime 2.0.11946 release with breaking changes for Java HttpTrigger Functions #57

Closed
pragnagopa opened this issue Jul 11, 2018 · 31 comments

Comments

@pragnagopa
Copy link
Member

pragnagopa commented Jul 11, 2018

Discussion issue for Azure/app-service-announcements#122

@pragnagopa
Copy link
Member Author

pragnagopa commented Jul 11, 2018

@TurtleBeach
Copy link

The new example shows building a response with a simple String. Is the .body(xxx).build() method capable of turning HashMaps into JSON automatically, as was previously the case prior to 2.0.11888 (using HttpRequestMessage.createResponse(HTTP_CODE, HashMap) when the function is defined to have a return type of HttpResponseMessage <HashMap<String, Object>>? This is critical to know, and I am not particularly interested in delving into MS source code.

@pragnagopa
Copy link
Member Author

@TurtleBeach - Yes. It should work. Can you please share code snippet? that will help us verify it.

@TurtleBeach
Copy link

TurtleBeach commented Jul 11, 2018

@pragnagopa Here is what ought to be a working function (extracted from a function that works with 2.0.11857). The returns are still with old syntax, but presumably you can see what I expect to accomplish. As you can also surmise, I will have to change every return in every Http triggered function (6 functions, structured similarly, so almost every error causes an immediate return. I don't want to start making changes until (1) you tell me the new methods work, and (2) the maven tooling is ready to support the new release. I was planning a soft launch next week - this throws a very large wrench into the works.
GitHub is acting strangely - I will try to attach a text file.
JSON Response Snippet.txt

Let me know if you can't see the file.
Snippet is below - sorry about layout, but the insert code caused the comment box to lock up the last time I tried to insert.

public class GetDataInfo
{
	private static final String FUNCTION_NAME = "GetDataInfo";
	
	private static final String statusProperty = "Status";
	private static final String modelsProperty = "Models";
	private static final String messageProperty = "UserMessage";
	private static final String errorProperty = "ErrorDetail";
	
	@FunctionName(FUNCTION_NAME)
	public HttpResponseMessage<HashMap<String, Object>> httpHandler(
            @HttpTrigger(name = "req", methods = {"post"}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<HashMap<String,Object>> request,
            final ExecutionContext context)
	{
		
		/*
			use Postman to send a POST (application/json) with this payload:
		
			{
			 "UserGUID":"initf692-cd76-4fc9-80c9-26fe77e3d33a"
			}		
		
		*/

		HashMap<String, Object> response = new HashMap<>();		// map for response
		
		int status = -1;
		String message = "JSON Error (Request Body)";
		String detail = "Error Detail Missing";
		
		response.put(statusProperty, status);					// assume an error here
		response.put(modelsProperty, false);
	
		Object body = request.getBody();
		if ( null == body )                         			// better never happen in production
		{
			detail = String.format( "Request body is null" );
			context.getLogger().severe( FUNCTION_NAME + " - " + detail );

			response.put(messageProperty, message);
			response.put(errorProperty, detail);
			return request.createResponse(HttpURLConnection.HTTP_BAD_REQUEST, response);	// PREVIOUS SYNTAX - used with 2.0.11857
		}
		
		if ( ! (body instanceof HashMap) )          			// application/json converts to Java LinkedHashMap
		{
			detail = String.format( "Request body is not a HashMap" );
			context.getLogger().severe( FUNCTION_NAME + " - " + detail );

			response.put(messageProperty, message);
			response.put(errorProperty, detail);
			return request.createResponse(HttpURLConnection.HTTP_BAD_REQUEST, response);	// PREVIOUS SYNTAX - used with 2.0.11857
		}

		@SuppressWarnings("unchecked")              	// 2017-11-19 eliminate compiler warning
		HashMap<String, Object> requestJSON = (HashMap<String, Object>) body;

		if ( requestJSON.isEmpty() )                  	// better never happen in production
		{
			detail = String.format( "Request body is empty" );
			context.getLogger().severe( FUNCTION_NAME + " - " + detail );

			response.put(messageProperty, message);
			response.put(errorProperty, detail);
			return request.createResponse(HttpURLConnection.HTTP_BAD_REQUEST, response);	// PREVIOUS SYNTAX - used with 2.0.11857
		}

		String userGUID = (String)requestJSON.get("UserGUID");
		String custGUID = (String)requestJSON.get("CustGUID");

		if ( (null == userGUID) )
		{
			message = "JSON Request Error (User GUID)";
			detail = String.format("Null User GUID");
			context.getLogger().severe( FUNCTION_NAME + " - " + detail );

			response.put(messageProperty, message);
			response.put(errorProperty, detail);
			return request.createResponse(HttpURLConnection.HTTP_BAD_REQUEST, response);	// PREVIOUS SYNTAX - used with 2.0.11857
		}

		if (userGUID.toLowerCase().startsWith("init")) 
		{
			response.put(statusProperty, 1);
			response.put(messageProperty, "Initializing");
			response.put(errorProperty, "");
			return request.createResponse(HttpURLConnection.HTTP_ACCEPTED, response);		// PREVIOUS SYNTAX - used with 2.0.11857
		}

		// more parameter checking and if all is well eventually HTTP_OK returned with response object suitably populated similar to ACCEPTED response above
	
	}
}

@pragnagopa
Copy link
Member Author

@TurtleBeach - We posted the announcement as a heads up. Runtime release has not started yet. I will update the announcement once I have the exact ETA for the release. And yes, we will have maven plugin to use with the runtime changes.
Can you update your comment with the code snippet?

@TurtleBeach
Copy link

TurtleBeach commented Jul 12, 2018

@pragnagopa I neglected to include samples of what I expect for return payloads, based on the code snippet:
Initializing Response payload (HTTP_ACCEPTED)
{
"Status": 1,
"ErrorDetail": "",
"Models": false,
"UserMessage": "Initializing"
}
Error (e.g. null User GUID) Response payload (HTTP_BAD_REQUEST)
{
"Status": -1,
"ErrorDetail": "Null User GUID",
"Models": false,
"UserMessage": "JSON Request Error (User GUID)"
}

@pragnagopa
Copy link
Member Author

Here is the simplified version of your code I verified

package Microsoft.Azure.WebJobs.Script.Tests.EndToEnd;

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

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

        String statusProperty = "Status";
	    String modelsProperty = "Models";

		HashMap<String, Object> response = new HashMap<>();
		
		int status = -1;
		String message = "JSON Error (Request Body)";
		String detail = "Error Detail Missing";
		
		response.put(statusProperty, status);					
		response.put(modelsProperty, false);
	
        String query = request.getQueryParameters().get("name");
        String name = request.getBody().orElse(query);
        
        if (name == null) {
            context.getLogger().info("Java HTTP trigger processed a request. name null");
            return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body(response).build();
        } else {
            context.getLogger().info("Java HTTP trigger processed a request. name not null");
            response.put(statusProperty, 2);					
		    response.put(modelsProperty, true);
            return request.createResponseBuilder(HttpStatus.OK).body(response).build();
        }
    }
}

Invocation result:

URL: http://localhost:55350/api/httptrigger-java?name=pgopa

HTTP/1.1 200 OK

{
  "Status": 2,
  "Models": true
}

URL: http://localhost:55350/api/httptrigger-java

HTTP/1.1 400 Bad Request

{
  "Status": -1,
  "Models": false
}

@TurtleBeach
Copy link

@pragnagopa Thanks!
When will the runtime (and maven tools) be rolled out, and will it be staged as apparently happened in the past (e.g., west central us seemed to get 2.0.11888 first, and eventually east us)?
I'd like to phase in using the new runtime one function at a time, but I don't want to start until I know the runtime is ready in east us.

@pragnagopa
Copy link
Member Author

maven tools are now available in staging repo. I have updated the announcement issue with instructions on how to use the tooling. Will update the annoucement again once I have the exact ETA for rolling out the runtime.

@betarabbit
Copy link

Hi @pragnagopa
Do we still need to use maven in staging repo? I suppose you have already done the deployment, thanks.

@jdneo
Copy link

jdneo commented Jul 31, 2018

@betarabbit Before the newest maven tools are published, staging repo is needed. Newest staging repo is https://oss.sonatype.org/content/repositories/commicrosoftazure-2491/

@betarabbit
Copy link

@jdneo Thanks for confirmation. Do you have an ETA for it, by the way?

@jdneo
Copy link

jdneo commented Jul 31, 2018

@betarabbit It will be about 1-2 days after the server side new runtime updated.

@lpawlik91
Copy link

@jdneo, all
I am new in Azure, so sorry for dummy question.
I saw in logs that "beta" is linked to old version, when I change FUNCTIONS_EXTENSION_VERSION manually to 2.0.11946-alpha (for beta-5) it shows me that kind of error/warning:

image

Is this is related with issues that you mention before (or others) and 2.0.11946-alpha runtime is not ready yet or I miss something?

@jdneo
Copy link

jdneo commented Aug 1, 2018

Hi @lpawlik91

@pragnagopa Could be better to answer this question.

But from my knowledge, the new runtime 2.0.11946-alpha hasn't been published yet.

@pragnagopa
Copy link
Member Author

@lpawlik91 - for using latest runtime beta is the right version. Deployment for 2.0.11946-alpha is still in progress. I will update the announcement issue once the release completes

@jdneo
Copy link

jdneo commented Aug 3, 2018

@ALL

New version of Azure Functions Maven plugin & archetype have been published:

Since it will take about 2-3 days for Maven Central to update the newest artifact version. So before the newest version is updated, you may need to explicit set the archetype version during generating:

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

@hf-kklein
Copy link

hf-kklein commented Aug 3, 2018

To anyone experiencing the same problem: Updating to maven-plugin beta-4 (with java-library beta-5) solves the problem with "Error: At least one binding has to be defined" error during runtime.

@hf-kklein
Copy link

hf-kklein commented Aug 3, 2018

@pragnagopa : Are the modificiations in settings.xml and pom.xml (pluginRepository) you mentioned in Azure/app-service-announcements#122 (comment) still necessary (besides the version change)?

@jdneo
Copy link

jdneo commented Aug 3, 2018

@hf-kklein No it's not necessary. The modification is used for staging verification. Since we have published tools to Maven Central. They can be removed.

Just update

  • plugin to beta-4
  • java-library to beta-5

is fine.

@jo3yk
Copy link

jo3yk commented Aug 6, 2018

Since the upgrade, I'm seeing that my functions no longer return an HTTP response - eventually timing out. I've created a new sample project using archetypeVersion=1.13 and the same issue occurs. Logging shows

    [06/08/2018 13:53:26] Executing 'Functions.HttpTrigger-Java' (Reason='This function was programmatically called via the host APIs.', Id=f51ddadf-8c2c-4201-8070-5f31b2147ac2)
    [06/08/2018 13:53:26] Java HTTP trigger processed a request.

But nothing is returned to the caller. Nothing further is logged.

This occurs both locally (using azure-functions:run, having updated the plugin to beta-4 and the java-library to beta-5) and when deployed to Azure.

Any advice on how to debug/resolve this issue?

@TurtleBeach
Copy link

@jo3yk I can only suggest looking carefully at your request.createResponse() code. I haven't started a new function from archetype, but after changing the maven and library references (along with getting the latest CLI code) my existing functions are working.

For what it's worth comments on 2.0.11946 deployment:

I am very disappointed that request.createResponseBuilder( ).body().build() still requires an enum. Assuming that MS eventually will support non-standard returns, I have to assume the argument will revert to an integer - which will entail another breaking change. Though I haven't looked at the source behind createResponseBuilder, I cannot imagine that it would have been hard to change the signature to an int now and do whatever was necessary inside the method to convert to an internal enum (though even an internal use of an enum is questionable in my view). Very frustrating.

The use of an enum as the HttpMethod in the Http triggered function signature is marginally more understandable, though it gets transformed to a String in the "function.json" file so I am not sure why that had to be changed too. I get the feeling someone read Blochs' books and decided everything in the world should be an enum without further thought.

The portal doesn't handle "WebHookType" : NONE in function.json in a way that makes sense to me. On the Azure portal, the default type for "Mode" is WebHook (it should be "Standard") - and more disconcerting, the type cannot be changed unless the function is running. Although it did not seem to affect my functions (I changed the mode to Standard, which then correctly set the Authentication to "function", which was in function.json, and also set the access method to POST, which was also in function.json), saved settings, and restarted the function and everything worked. I fear, however, that a default mode setting of WebHook will eventually cause problems if the real mode should be "Standard".

@jo3yk
Copy link

jo3yk commented Aug 6, 2018

@TurtleBeach Thanks for your reply. On the new sample project, I haven't made any changes to the generated code, I'm just trying (and failing) to run it as-is - so the response code is simply

return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();

@TurtleBeach
Copy link

Are you sure you have V2 CLI installed? I don't pretend to understand all the convoluted interactions between the libraries, maven, and CLI, but I do know they must be in synch. Scroll down to V2 Windows (assuming you are on a Windows platform:
https://github.com/Azure/azure-functions-core-tools

@pragnagopa pragnagopa changed the title [Discussion] Azure Functions Runtime x release with breaking changes for Java HttpTrigger Functions [Discussion] Azure Functions Runtime 2.0.11946 release with breaking changes for Java HttpTrigger Functions Aug 6, 2018
@jo3yk
Copy link

jo3yk commented Aug 6, 2018

Thanks for the idea @TurtleBeach. I had v2.0.1-beta31 installed. I've just upgraded to v2.0.1-beta33, but it's made no difference.

On further testing, the issue does seem to be specific to HttpResponseMessage - if I return a String instead, I get a response. In the HttpResponseMessage case, no exceptions are thrown, the function just seems to hang.

It would be good to get some input from Microsoft.

@hf-kklein
Copy link

hf-kklein commented Aug 6, 2018 via email

@pragnagopa
Copy link
Member Author

@jo3yk - Please install latest version of Azure Functions CLI 2.0.1-beta.34 and run func, it should show following version info:

Azure Functions Core Tools (2.0.1-beta.34)
Function Runtime Version: 2.0.11946.0

@jo3yk
Copy link

jo3yk commented Aug 6, 2018

@hf-kklein Sure, the version that hangs is the unmodified generated archetype, using archetypeVersion=1.13. So the function is:

         @FunctionName("HttpTrigger-Java")
             public HttpResponseMessage HttpTriggerJava(
        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.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.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
    } else {
        return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
    }
}

The working version simply changes the return type to String:

         @FunctionName("HttpTrigger-JavaStringResp")
             public String HttpTriggerJavaStringResp(
        @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.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 "Please pass a name on the query string or in the request body";
    } else {
        return "Hello, " + name;
    }
}

@pragnagopa I've upgraded to the latest version using chocolatey, that's 2.0.1-beta33. Do I have to use NPM instead to install beta34? And if so, do I need to uninstall the chocolatey version first?

@pragnagopa
Copy link
Member Author

@jo3yk - We will publish to chocolatey soon.
@ahmelsayed - Can you please push an update?

@ahmelsayed
Copy link

ahmelsayed commented Aug 6, 2018

I just updated chocolatey and APT with the latest release

@jo3yk
Copy link

jo3yk commented Aug 7, 2018

@pragnagopa @ahmelsayed Thanks for making the update available - I can confirm that everything appears to be working now that I've upgraded. Thanks for your help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants