Closed lafernando closed 4 years ago
I think this is related to https://github.com/Azure/azure-functions-host/pull/6308
It should be fixed now, please try again. If it’s not working in core tools, there should be a new release published soon.
Cc @pragnagopa @yojagad
Thanks for reporting. Closing as this should be fixed now. Please reopen if you still run into an issue.
Hi guys,
I just tested this again, and I'm afraid, I still get the same issue.
The following is the log:-
2020-08-20T22:39:11.151 [Information] Executing 'Functions.hello' (Reason='This function was programmatically called via the host APIs.', Id=b2a5db8a-c41d-48d8-b0c4-01903ec80ca0)
2020-08-20T22:39:11.221 [Error] Executed 'Functions.hello' (Failed, Id=b2a5db8a-c41d-48d8-b0c4-01903ec80ca0, Duration=41ms)
No MediaTypeFormatter is available to read an object of type 'HttpScriptInvocationResult' from content with media type 'text/plain'.
Function App name: functions1777
@pragnagopa @anthonychu Also, it seems I don't have enough privileges to re-open this issue.
@yojagad - Please investigate.
@lafernando - can you please share host.json
contents?
Hi,
Yes, please find it below.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "java",
"defaultWorkerPath": "t.jar",
"arguments": [
"-jar"
]
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
@lafernando - I see you are using the new config section. Forwarding http request is opt-in. Can you please re-try after adding "enableForwardingHttpRequest":true
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "java",
"defaultWorkerPath": "t.jar",
"arguments": [
"-jar"
]
},
"enableForwardingHttpRequest":true
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
We are in the process of updating sample and docs, Please see PR https://github.com/Azure/azure-functions-host/issues/6178 for updated samples.
@pragnagopa - Now I'm getting the following error from my function:
no matching resource found for path : /api/hello , method : POST
This error is coming from the Ballerina custom handler, and it is because, now the custom handler is invoked with the context "/api/hello", earlier it used to be just "/hello". For other non-pure HTTP invocations, I guess the handler will be invoked without the "/api" part?
custom handler is invoked with the context "/api/hello", earlier it used to be just "/hello"
Yes, with the new config we made forwarding simpler. Request will be sent on the same route as original invocation.
For other non-pure HTTP invocations, I guess the handler will be invoked without the "/api" part
That is correct.
Our docs will be updated soon with this info. Thanks!
custom handler is invoked with the context "/api/hello", earlier it used to be just "/hello"
Yes, with the new config we made forwarding simpler. Request will be sent on the same route as original invocation.
But for example, the "/api" part is mandatory right?, I tried invoking my earlier service with "https://functions1777.azurewebsites.net/hello" and I got a 404. So if "/api" part is anyway going to be there always, wouldn't it make sense to retain the earlier functionality? Also, since now the request come with "/api/" to the handler, now there's a possibility of clashing it with a function that is exposed with the name "api". It seems the situation may have become a bit more complicated :).
For other non-pure HTTP invocations, I guess the handler will be invoked without the "/api" part
That is correct.
Our docs will be updated soon with this info. Thanks!
Please see https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=csharp#customize-the-http-endpoint for information on how http trigger routes work in Azure functions.
Closing this as resolved.
@pragnagopa I got it, now the custom handler also get the same route as the original request always, and the function name is not involved now. By any chance, is it still possible to get the earlier behavior, maybe without the use of "enableForwardingHttpRequest" flag, where we can still get the HTTP triggered requests invoking the custom handler with the function name? since we can anyway retrieve path parameter information with input bindings, the handler function dispatching would be much simpler/cleaner with the function name in the request.
@anthonychu Let me put a little bit more context into my request. Unlike a simple custom handler implementation, where the user will implement the handler itself each time writing a function, in a situation like in Ballerina, we automatically generate a handler, which is implemented using a single service, that it will read in the full request path, and by looking at the request path, dispatch it to the functions that are registered.
Earlier, since it used to be that, the path component sent to the handler directly contains the function name, this dispatch was straightforward. But with this new change, we have a situation where for HTTP triggers, we need to do our own mapping of HTTP routes to the function names we have. So when we have multiple routes such as "products/{category:alpha}/{id:int?}" with multiple functions together, the single handler have to resolve different path patterns to a specific function targets. This operation is already done by Azure Functions, and now the handler itself have to implement this logic, which probably can get complicated, with all the patterns supported there, and considering possible priority orders if there are ambiguous situations and so on. I hope my concern is clear here. So it would be great if we can still have a flag with the new configuration, in order for the HTTP trigger based functions to behave in the earlier way as well.
Setting enableForwardingHttpRequest
to false
will invoke the handler at /functionname
. The reason we made the change is precisely to remove the need for code like this, where the custom handler needs a special case to deal with a pure HTTP function. Your function dispatcher can now have a single code path no matter what the triggers and bindings are on the function.
As for the case of products/{category:alpha}/{id:int?}
, I don't believe the old httpWorker
behavior allowed the handler to get the values of the route if it's a pure HTTP function. With customHandler
, you can get this information in the payload (with enableForwardingHttpRequest=false
) or get it from the HTTP request route (enableForwardingHttpRequest=true
).
Setting
enableForwardingHttpRequest
tofalse
will invoke the handler at/functionname
. The reason we made the change is precisely to remove the need for code like this, where the custom handler needs a special case to deal with a pure HTTP function. Your function dispatcher can now have a single code path no matter what the triggers and bindings are on the function.
@anthonychu That is great! so that means, in the case of a pure HTTP function also (with enableForwardingHttpRequest=false), we would get a JSON payload with a structure like below:
{
"Data": {
"httpReq": "{ message: \"Message sent\" }"
},
"Metadata": { .. }
}
And yes, with this, we can certainly make the handler generation code much simpler as you pointed out.
Unfortunately, I'm still getting my original issue that I got when I reported this issue (No MediaTypeFormatter is available to read an object of type 'HttpScriptInvocationResult' from content with media type 'text/plain'.). I'm getting this with the following host.json:-
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "java",
"defaultWorkerPath": "t.jar",
"arguments": [
"-jar"
]
},
"enableForwardingHttpRequest":false
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
If we can get this scenario to work, that would be great.
As for the case of
products/{category:alpha}/{id:int?}
, I don't believe the oldhttpWorker
behavior allowed the handler to get the values of the route if it's a pure HTTP function. WithcustomHandler
, you can get this information in the payload (withenableForwardingHttpRequest=false
) or get it from the HTTP request route (enableForwardingHttpRequest=true
).
Yes, that's my bad, you're correct, earlier with pure HTTP functions we couldn't have input bindings defined, since the payload cannot have that info.
@lafernando I just tested out a pure HTTP function with enableForwardingHttpRequest=false
and it worked as expected.
With enableForwardingHttpRequest=false
, every request to the handler is an HTTP POST. Check that your handler is not getting a 404 on the request.
In one of the future releases of Core Tools, we'll have more trace level logging that will help you diagnose the requests and responses to/from the handler.
@anthonychu I found the issue! earlier I was sending out the HTTP payload directly from the handler, without wrapping it in the '{"Data":{"req":...}' format (with the enableForwardingHttpRequest=true format). The Azure Functions runtime expected this JSON value, and not seeing that, it has printed the earlier error. The change was simply removing the special casing of pure HTTP function handler generation in my code, and using the general logic.
Thanks a lot, and appreciate taking your time to look into this!
No problem. Thanks for all the work on bringing Ballerina to Azure Functions. Please share any feedback you have and let us know if you run into any issues with the new changes. We hope to publish the docs for the new customHandler
section soon (when the next version of Core Tools is released).
Certainly! It's a great system, and very much enjoyed doing the Ballerina implementation. I will surely provide more feedback whenever applicable! Thank you!
I'm using the Ballerina language's custom Azure Functions handler in implementing a pure HTTP function. The code is as follows.
I built, deployed, and invoked the function in the following manner:
The logs in Azure Functions App show the following:
I tried invoking the function with different content types as the input, but I still get the same log. This functionality used to work a little while back (I tested this scenario lastly on July 23'rd 2020), and it's just starting to fail now. Did something change recently in relation to pure HTTP functions? any assistance on this matter is appreciated.
Investigative information
Timestamp: functions1777 Function App version: 2.0 Function App name: functions1777 Function name(s): hello Invocation ID: c9287ccd-3d0f-4285-b4ba-3ae4f7ec1287 Region: East US