Search code examples
c#azure-functionsconnection-timeoutazure-functions-runtime

Timeout HttpClient inside AzureFunction


I have here a piece of code that calls a different api inside of azure functions. that request takes a while if it takes longer than 4 minutes the client will timeout, not the functions itself. Here is my code

Code in program.cs

 {
     client.BaseAddress = new Uri(Environment.GetEnvironmentVariable("MONO_CHAT_URL") ?? throw new NullReferenceException("Mono chat url cannot be null"));
     client.DefaultRequestHeaders.Add("keyname", Environment.GetEnvironmentVariable("API_KEY") ?? throw new NullReferenceException("API Key cannot be null"));
     client.Timeout = TimeSpan.FromSeconds(9999);
 });`

Code in a service

  {
      try
      {
          _logger.LogInformation("Request is send to {BaseUrl}/{Path}", client.BaseAddress, path);
          var response = await client.GetFromJsonAsync<T>(path);
          if (response != null)
          {
              _logger.LogInformation("Response recieved for {path}", path);
              if (response.GetType() != typeof(T))
              {
                  _logger.LogError("Response with url {BaseUrl}/{Path} is not the correct type", client.BaseAddress , path);
              }
          }
          else
          {
              _logger.LogError("Response with url {BaseUrl}/{Path} is empty", client.BaseAddress, path);
          }
          return response;
      }
      catch (Exception e)
      {
          _logger.LogError(e, "Could not get data for {path}", path);
          throw e;
      }

  }

Localy it works just fine because it gets the client timeout from the program.cs but i have a feeling that when deployed to azure, azure function sets its own client timout based on this RequestTimout


Solution

  • HttpClient gets timed out after 230 seconds and will also get timeout if you have set it beyond 230 seconds due to the following limitation of Azure load balancer.

    enter image description here

    • If your API takes more than 4 minutes to respond then you can consider using Azure durable function.
    • I am calling a function in azure durable function which takes 5mins to respond.
    using System;
    using System.Threading.Tasks;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.Http;
    using Microsoft.Extensions.Logging;
    using System.Net.Http;
    using Microsoft.Azure.WebJobs.Extensions.DurableTask;
    
    namespace _78538129_1
    {
        public static class DurableFunction
        {
    
            [FunctionName("DurableFunction")]
            public static async Task RunOrchestrator(
                [OrchestrationTrigger] IDurableOrchestrationContext context)
            {
                // Call Function1
                await context.CallActivityAsync("ActivityFunction", null);
            }
    
            [FunctionName("ActivityFunction")]
            public static async Task CallFunction1([ActivityTrigger] object input, ILogger log)
            {
                var httpClient = new HttpClient();
                httpClient.Timeout = TimeSpan.FromMinutes(7);
                var response = await httpClient.GetAsync("https://****.azurewebsites.net/api/Function1");
    
                if (!response.IsSuccessStatusCode)
                {
                    throw new Exception($"Function1 failed with status code {response.StatusCode}");
                }
    
                log.LogInformation("Function1 called successfully.");
            }
    
            [FunctionName("HttpStart_DurableFunction")]
            public static async Task<HttpResponseMessage> HttpStart(
                [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestMessage req,
                [DurableClient] IDurableOrchestrationClient starter,
                ILogger log)
            {
                // Function input comes from the request content.
                string instanceId = await starter.StartNewAsync("DurableFunction", null);
    
                log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
    
                return starter.CreateCheckStatusResponse(req, instanceId);
            }
        }
    }
    

    You can modify the durable function as per your requirement.