SocketError when creating multiple HttpClient Connections with the Load balancer(F5)

188 views Asked by At

This is the exact exception in the error logs.

enter image description here

I have a requirement where I should be creating a set of service calls and wait till all of them are completed successfully before moving on to do a different set of service calls.

I have two services Service1 and Service2. There are 2 instances of Service2 in 2 different servers and we have set up an F5(Load Balancer) to distribute the load evenly.

Let's say I have 10 service calls to be made from Service1 to Service2 at a time and F5 will share those 10 calls among the 2 servers. i.e. 5 Calls to Service2 of each server.

But I observed that if any one of those 10calls is taking lot of time to complete the work it should do(The work to be done in Service2 has some heavy lifting) then i get a socket exception thrown and entire process gets stopped.

However when I dont use the F5 load balancer and just use 1 instance of the Service2. Then however long the process takes for any of those 10 calls it doesn't throw any exception.

I am not sure if this is an issue with F5 configuration or with the way connections are made with the F5 from .Net code.

Please go through the below code to get some idea of what i am trying to do and let me know if any code change would help me resolve it.

for (int i=0 ; i< ReqList.Count;i++)
{
  maxTasks++;
  ClassA reqList = new ClassA();
  reqList = ReqList[i];
  List<ClassA> recsByReq = recs.Where(x => x.ReqId == reqList.ReqtId).ToList();
  ClassC service2Input = new ClassC();
  service2Input.DetaiList = listofRecs;
  service2Input.RecList = recsByReq;
  taskList.Add(_service2.Service2MethodCall(service2Input, service2Resource));
  if(maxTasks == 10 || ReqList.Count == 10 || i==ReqList.Count-1)
  {
    Task.WaitAll(taskList.ToArray(),-1);
    maxTasks = 0;
    taskList.Clear();
  }
                

}

The Service2MethodCall is where I am creating a HttpClient to make connections with the 2nd service i.e. Service2,

public class Service2: IService2 {
  
private ServiceClient GetService2(string resource) 
{
 return new ServiceClient(_service2BaseUrl,        TimeSpan.FromMinutes(60)) 
 {
    Resource = resource,
 };
}
public async Task Service2MethodCall(ClassC service2Input, string resource) 
{
 try 
 {
   var client = GetService2(resource);
   await     client.PostAsync(JsonConvert.SerializeObject(service2Input).ToString());
 } 
 catch (Exception ex) 
 {
   throw new Exception("The Service encountered an error during the Service2 call for Req ID : " +
        service2Input.RecsList.Find(x => x.ReqId != "").ReqId.ToString(), ex);
 }
}
}

The PostAsync() method creates a new HttpClient with HttpClientHandler object for each of the call.

public async Task PostAsync(object data) {
  using(var httpClientHandler = new HttpClientHandler()) {
    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => {
      if (sslPolicyErrors == SslPolicyErrors.None) {
        return true; //Is valid
      }

      if (cert.GetCertHashString().ToUpper() == _acceptedThumbprint.ToUpper()) {
        return true;
      }
      return false;
    };
    using(var client = new HttpClient(httpClientHandler)) {
      client.DefaultRequestHeaders.Accept.Clear();
      client.DefaultRequestHeaders.Accept.Add(ResponseFormatter.MediaType);
      client.Timeout = Timeout.InfiniteTimeSpan;
      Uri uri = BuildUri();
      if (!String.IsNullOrWhiteSpace(SignatureKey)) {
        client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization",
          RequestFormatter.GenerateAuthHeaderEncodedUserSignature(uri, AuthUserName, SignatureKey, data));
      }
      //_logger.WriteUsage(client.BaseAddress.ToString());
      HttpResponseMessage response = await RequestFormatter.PostAsync(client, uri, data);
      string content = await response.Content.ReadAsStringAsync();
      try {
        response.EnsureSuccessStatusCode();
      }#
      pragma warning disable CS0168 // The variable 'rex' is declared but never used
      catch (HttpRequestException rex)# pragma warning restore CS0168 // The variable 'rex' is declared but never used
      {
        //_logger.WriteUsage("Response for POST to: {0} did not yield a successful status code. Message: {1}" + uri.ToString() + content);
        throw new ApiHttpException(response.StatusCode, content);
      }
    }
  }
}

Is there some thing I can do within the code to avoid this situation once and for all?

0

There are 0 answers