4

I am working on two functions in Azure Functions

Timer Function and Http Trigger Function

My timer functions runs every 1 hour and it executes the http function via an Http Client.

Now I do get an error Synchronous operations are disallowed

And I know how to solve this using the article on stack overflow

But I am curious as why am I getting this error?

Whats the cause of it?

The error doesn't occur when using Postman.

My Timer Code

Azure Functions Core Tools (3.0.2245 Commit hash: 1d094e2f3ef79b9a478a1621ea7ec3f93ac1910d)
Function Runtime Version: 3.0.13139.0

 Host configuration file read:
{
   "version": "2.0"
}
public static class DoSomeStuffTimer
    {
        [FunctionName("DoSomeStuffTimer")]
        public static void Run([TimerTrigger("0 0 7 * * *")]TimerInfo myTimer, ILogger log)
        {
            try
            {
                log.LogInformation($"C# DoSomeStuffTimer executing at: {DateTime.Now}");
                string url = Environment.GetEnvironmentVariable(EnvironmentKey.HostKey) + "/api/DoSomeStuff";
                HttpClient client = new HttpClient();
                client.PostAsJsonAsync(url, new DoSomeStuffRequest());
                log.LogInformation($"C# DoSomeStuffTimer executed at: {DateTime.Now}");
            }
            catch (Exception e)
            {
                log.LogInformation(e.ToString());
            }
        }
    }

My Http Code

public class DoSomeStuffFunction
    {
        [FunctionName("DoSomeStuffFunction")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = "DoSomeStuff")]
            HttpRequestMessage req,
            ILogger log)
        {
            var response = new ContentResult {ContentType = "application/json", StatusCode = 200};

            try
            {
                DoSomeStuffRequest
                    request = req.Content.ReadAsAsync<DoSomeStuffRequest>().Result;
    }
catch (Exception e)
            {
                log.LogInformation(e.ToString());
            }
}
}

RoadRunner
  • 25,803
  • 6
  • 42
  • 75
Noob Coder
  • 444
  • 1
  • 5
  • 16

2 Answers2

3

Starting with ASP.NET Core 3.0 synchronous calls are disabled by default So any function running on 3.0 will encounter this when it tries to do synchronous calls

I looked into it and found the reason why it happens in your function is that ReadAsAsync<>() somewhere in it's operation does something synchronously. I am not sure exactly why it does this or why it doesn't break when you call the httptrigger directly. That'll require quite a bit more work to figure out.

To make your code work without FUNCTIONS_V2_COMPATIBILITY_MODE set to True you can use one of the other readers, for example ReadAsStreamAsync() instead.

Below you can find the method that works (I tested it locally). However, I would not recommend you call another function in your function app directly and instead follow the recommendations by Microsoft or create an abstraction that contains the logic that both functions can call on independently.

public class DoSomeStuffFunction
{
    [FunctionName("DoSomeStuffFunction")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = "DoSomeStuff")]
        HttpRequestMessage req,
        ILogger log)
    {
        var response = new ContentResult { ContentType = "application/json", StatusCode = 200 };

        try
        {
            var request = await req.Content.ReadAsStreamAsync();
            using (StreamReader rd = new StreamReader(request))
            {
                var result = JsonConvert.DeserializeObject<DoSomeStuffRequest>(await rd.ReadToEndAsync()).;
            }

            return new OkObjectResult(response);
        }
        catch (Exception e)
        {
            log.LogInformation(e.ToString());
            return new BadRequestObjectResult("It went wrong");
        }
    }
}
AimusSage
  • 696
  • 4
  • 5
0

The solution you mentioned is to set the variable FUNCTIONS_V2_COMPATIBILITY_MODE to true. We can see some information about this variable in this page.

enter image description here

So,did you do the operation to upgraded your function from v2 to v3 ? It may cause this issue.

Update:

I test it in my side on local visual studio. When I create the function app in visual studio, I choose azure function v3(.net core). And below is my code, it works fine without any error.

namespace FunctionApp8
{
    public static class Function2
    {
        [FunctionName("Function2")]
        public static void Run([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, ILogger log)
        {
            log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
            string url = "http://localhost:7071/api/triggerFunction";
            HttpClient client = new HttpClient();
            client.PostAsJsonAsync(url, "");
            log.LogInformation($"C# DoSomeStuffTimer executed at: {DateTime.Now}");
        }
    }
}
namespace FunctionApp8
{
    public static class Function1
    {
        [FunctionName("triggerFunction")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            return (ActionResult)new OkObjectResult($"Hello");
        }
    }
}

I'm not sure if your function app is related to .net core 2.x. So could you please follow the steps recreate another function app(check if your visual studio has been updated to the lastest version and choose Azure Function v3 .NET core at the beginning) and test if it works fine.

Hury Shen
  • 14,948
  • 1
  • 9
  • 18
  • My app is running on dotnet core 3.0, and in the host json version is set to 2 – Noob Coder Mar 19 '20 at 06:07
  • Although the error doesn't occur when I hit the trigger via Postman – Noob Coder Mar 19 '20 at 06:08
  • @NoobCoder Could you please check if the error is related to the timer function(the runtime version of your timer function). – Hury Shen Mar 19 '20 at 06:13
  • @NoobCoder As far as I know, the version in host.json will not change even if you create v3 function (refer to this [tutorial](https://learn.microsoft.com/en-us/azure/azure-functions/functions-host-json#version)). It is always going to be 2.0. – Hury Shen Mar 19 '20 at 06:37
  • @NoobCoder May I know if your function app was created in the past and then when you publish the code from visual studio, you choose this function app ? Or when you publish the code from visual studio, you create a new function app ? – Hury Shen Mar 19 '20 at 06:39
  • No I am just doing testing locally I haven't publish this anywhere. – Noob Coder Mar 19 '20 at 07:26
  • Hi @NoobCoder I test it in my side but it works fine. Please check my update in answer area. – Hury Shen Mar 19 '20 at 08:10
  • @HuryShen the reason your code works without setting `FUNCTIONS_V2_COMPATIBILITY_MODE` mode to `True` is because you are not doing any operations on the request in the http trigger that would cause the exception. – AimusSage Mar 19 '20 at 09:47
  • @AimusSage Thanks for pointing it out. Do you know why it will cause this error in Noob's function ? All I know is the upgrading from .net core 2.x to .net core 3.x will cause this error, but Noob said his function is .net core 3.0. – Hury Shen Mar 19 '20 at 09:54
  • Starting with .Net Core 3.0 [synchronous calls are disabled by default](https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnetcore#http-synchronous-io-disabled-in-all-servers) So any function running on 3.0 will encounter this when it tries to do synchronous calls. I'm not sure what causes it with Noob's function, I'll have to look into it. – AimusSage Mar 19 '20 at 10:15
  • How can this code actually work when this call is not awaited?! `client.PostAsJsonAsync(url, "");` – silent Mar 19 '20 at 10:27
  • @NoobCoder, Just as a general recommendation, it is usally better to not call another function in you function app directly, but instead abstract the logic into a shared dependency that both methods can call directly or [use one of these methods](https://learn.microsoft.com/en-us/azure/azure-functions/functions-best-practices#cross-function-communication) – AimusSage Mar 19 '20 at 10:30
  • The version number in host.json of host.json is the schema version of the host.json file. It has nothing to do with the Function runtime or the .Net Core version running. – CodeMonkey Feb 15 '21 at 14:13