// Executes the asynchronous method with load balancing in case of virtual network internal TResult ExecuteAndGetWithVirtualNetworkLoadBalancing <TResult>(Func <string, Task <TResult> > method) { if (_loadBalancer == null) { return(method.Invoke(null).Result); } else { TResult result = default(TResult); int numRetries = _loadBalancer.GetNumAvailableEndpoints(); LoadBalancingHelper.Execute(() => { var endpoint = _loadBalancer.GetEndpoint(); Contract.Assert(endpoint != null, "Load balancer failed to return a worker node endpoint!"); Trace.TraceInformation("\tIssuing request to endpoint " + endpoint); try { result = method.Invoke(endpoint.ToString()).Result; _loadBalancer.RecordSuccess(endpoint); } catch (Exception) { _loadBalancer.RecordFailure(endpoint); throw; } }, new RetryOnAllExceptionsPolicy(), new NoOpBackOffScheme(), numRetries: numRetries); return(result); } }
/// <summary> /// Issues the web request asynchronous. /// </summary> /// <param name="endpoint">The endpoint.</param> /// <param name="method">The method.</param> /// <param name="input">The input.</param> /// <param name="options">request options</param> /// <returns></returns> public async Task <Response> IssueWebRequestAsync(string endpoint, string query, string method, Stream input, RequestOptions options) { options.Validate(); var watch = Stopwatch.StartNew(); Trace.CorrelationManager.ActivityId = Guid.NewGuid(); var balancedEndpoint = _balancer.GetEndpoint(); // Grab the host. Use the alternative host if one is specified var host = options.AlternativeHost != null ? options.AlternativeHost : balancedEndpoint.Host; var builder = new UriBuilder( balancedEndpoint.Scheme, host, options.Port, options.AlternativeEndpoint + endpoint); if (query != null) { builder.Query = query; } var target = builder.Uri; try { Debug.WriteLine("Issuing request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, target); var httpWebRequest = WebRequest.CreateHttp(target); //httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize; //httpWebRequest.ServicePoint.UseNagleAlgorithm = options.UseNagle; httpWebRequest.Timeout = options.TimeoutMillis; // This has no influence for calls that are made Async httpWebRequest.KeepAlive = options.KeepAlive; httpWebRequest.Credentials = _credentialCache; httpWebRequest.PreAuthenticate = true; httpWebRequest.Method = method; httpWebRequest.Accept = _contentType; httpWebRequest.ContentType = _contentType; // This allows 304 (NotModified) requests to catch //https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowautoredirect(v=vs.110).aspx httpWebRequest.AllowAutoRedirect = false; if (options.AdditionalHeaders != null) { foreach (var kv in options.AdditionalHeaders) { httpWebRequest.Headers.Add(kv.Key, kv.Value); } } long remainingTime = options.TimeoutMillis; if (input != null) { // expecting the caller to seek to the beginning or to the location where it needs to be copied from Stream req = null; try { req = await httpWebRequest.GetRequestStreamAsync().WithTimeout( TimeSpan.FromMilliseconds(remainingTime), "Waiting for RequestStream"); remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds; if (remainingTime <= 0) { remainingTime = 0; } await input.CopyToAsync(req).WithTimeout( TimeSpan.FromMilliseconds(remainingTime), "Waiting for CopyToAsync", CancellationToken.None); } catch (TimeoutException) { httpWebRequest.Abort(); throw; } finally { if (req != null) { req.Close(); } } } try { remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds; if (remainingTime <= 0) { remainingTime = 0; } Debug.WriteLine("Waiting for response for request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, target); var response = (HttpWebResponse)await httpWebRequest.GetResponseAsync().WithTimeout( TimeSpan.FromMilliseconds(remainingTime), "Waiting for GetResponseAsync"); Debug.WriteLine("Web request {0} to endpoint {1} successful!", Trace.CorrelationManager.ActivityId, target); return(new Response { WebResponse = response, RequestLatency = watch.Elapsed, PostRequestAction = r => { if (r.WebResponse.StatusCode == HttpStatusCode.OK || r.WebResponse.StatusCode == HttpStatusCode.Created || r.WebResponse.StatusCode == HttpStatusCode.NotModified) { _balancer.RecordSuccess(balancedEndpoint); } else { _balancer.RecordFailure(balancedEndpoint); } } }); } catch (TimeoutException) { httpWebRequest.Abort(); throw; } } catch (WebException we) { // 404 is valid response var resp = we.Response as HttpWebResponse; if (resp.StatusCode == HttpStatusCode.NotFound) { _balancer.RecordSuccess(balancedEndpoint); Debug.WriteLine("Web request {0} to endpoint {1} successful!", Trace.CorrelationManager.ActivityId, target); } else { _balancer.RecordFailure(balancedEndpoint); Debug.WriteLine("Web request {0} to endpoint {1} failed!", Trace.CorrelationManager.ActivityId, target); } throw we; } catch (Exception e) { _balancer.RecordFailure(balancedEndpoint); Debug.WriteLine("Web request {0} to endpoint {1} failed!", Trace.CorrelationManager.ActivityId, target); throw e; } }