public async Task ProcessRequest_MaxParallelism_RequestsAreThrottled() { int maxParallelism = 3; int count = 0; Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > process = async(req, ct) => { if (Interlocked.Increment(ref count) > maxParallelism) { throw new Exception("Kaboom!"); } await Task.Delay(100); Interlocked.Decrement(ref count); return(new HttpResponseMessage(HttpStatusCode.OK)); }; var config = new HttpExtensionConfiguration { MaxConcurrentRequests = maxParallelism }; var manager = new HttpRequestManager(config, _traceWriter); // expect all requests to succeed var tasks = new List <Task <HttpResponseMessage> >(); for (int i = 0; i < 20; i++) { var request = new HttpRequestMessage(); tasks.Add(manager.ProcessRequestAsync(request, process, CancellationToken.None)); } await Task.WhenAll(tasks); Assert.True(tasks.All(p => p.Result.StatusCode == HttpStatusCode.OK)); }
public override void Initialize() { // Apply Blobs configuration // TODO: FACAVAL - Follow up on TEMP comment below Config.Blobs.CentralizedPoisonQueue = true; // TEMP : In the next release we'll remove this and accept the core SDK default var configSection = (JObject)Metadata["blobs"]; JToken value = null; if (configSection != null) { if (configSection.TryGetValue("centralizedPoisonQueue", out value)) { Config.Blobs.CentralizedPoisonQueue = (bool)value; } } // apply http configuration configuration configSection = (JObject)Metadata["http"]; HttpExtensionConfiguration httpConfig = null; if (configSection != null) { httpConfig = configSection.ToObject <HttpExtensionConfiguration>(); } httpConfig = httpConfig ?? new HttpExtensionConfiguration(); httpConfig.SetResponse = HttpBinding.SetResponse; Config.UseScriptExtensions(); Config.UseHttp(httpConfig); }
public override void Initialize() { // Apply Blobs configuration var configSection = (JObject)Metadata["blobs"]; JToken value = null; if (configSection != null) { if (configSection.TryGetValue("centralizedPoisonQueue", out value)) { Config.Blobs.CentralizedPoisonQueue = (bool)value; } } // apply http configuration configuration configSection = (JObject)Metadata["http"]; HttpExtensionConfiguration httpConfig = null; if (configSection != null) { httpConfig = configSection.ToObject <HttpExtensionConfiguration>(); } httpConfig = httpConfig ?? new HttpExtensionConfiguration(); httpConfig.SetResponse = HttpBinding.SetResponse; Config.UseScriptExtensions(); Config.UseHttp(httpConfig); }
public async Task ProcessRequest_HostIsOverloaded_CustomRejectAction() { bool rejectOverrideCalled = false; var config = new HttpExtensionConfiguration(); Func <bool> rejectAllRequests = () => { return(true); }; Func <HttpRequestMessage, HttpResponseMessage> rejectRequest = (req) => { rejectOverrideCalled = true; return(new HttpResponseMessage(HttpStatusCode.ServiceUnavailable)); }; Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > process = (req, ct) => { return(Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK))); }; var manager = new TestHttpRequestManager(config, _traceWriter, rejectAllRequests, rejectRequest); var request = new HttpRequestMessage(); var response = await manager.ProcessRequestAsync(request, process, CancellationToken.None); Assert.True(rejectOverrideCalled); Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode); }
public async Task ProcessRequest_HostIsOverloaded_RequestsAreRejected() { bool rejectRequests = false; var config = new HttpExtensionConfiguration(); Func <bool> rejectAllRequests = () => { return(rejectRequests); }; Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > process = async(req, ct) => { await Task.Delay(100); return(new HttpResponseMessage(HttpStatusCode.OK)); }; var manager = new TestHttpRequestManager(config, _traceWriter, rejectAllRequests); var tasks = new List <Task <HttpResponseMessage> >(); for (int i = 0; i < 10; i++) { if (i == 7) { rejectRequests = true; } var request = new HttpRequestMessage(); tasks.Add(manager.ProcessRequestAsync(request, process, CancellationToken.None)); } await Task.WhenAll(tasks); Assert.Equal(7, tasks.Count(p => p.Result.StatusCode == HttpStatusCode.OK)); Assert.Equal(3, tasks.Count(p => p.Result.StatusCode == (HttpStatusCode)429)); }
private void InitializeHttp() { // get the registered http configuration from the extension registry var extensions = Instance.ScriptConfig.HostConfig.GetService <IExtensionRegistry>(); HttpExtensionConfiguration httpConfig = extensions.GetExtensions <IExtensionConfigProvider>().OfType <HttpExtensionConfiguration>().Single(); InitializeHttpFunctions(Instance.Functions, httpConfig); }
public WebScriptHostRequestManagerTests() { _metricsLogger = new Mock <IMetricsLogger>(MockBehavior.Strict); _performanceManager = new Mock <HostPerformanceManager>(MockBehavior.Strict, new object[] { new ScriptSettingsManager(), new HostHealthMonitorConfiguration() }); _httpConfig = new HttpExtensionConfiguration(); _traceWriter = new TestTraceWriter(TraceLevel.Verbose); _requestManager = new WebScriptHostRequestManager(_httpConfig, _performanceManager.Object, _metricsLogger.Object, _traceWriter, 1); _functionDescriptor = new FunctionDescriptor("Test", null, null, new Collection <ParameterDescriptor>(), null, null, null); }
public HttpTriggerEndToEndTests() { var httpConfig = new HttpExtensionConfiguration(); httpConfig.SetResponse = SetResultHook; _config = new JobHostConfiguration { TypeLocator = new ExplicitTypeLocator(typeof(TestFunctions)) }; _config.UseHttp(httpConfig); _host = new JobHost(_config); }
public HttpTriggerEndToEndTests() { var httpConfig = new HttpExtensionConfiguration(); httpConfig.SetResponse = SetResultHook; _config = new JobHostConfiguration { TypeLocator = new ExplicitTypeLocator(typeof(TestFunctions)) }; _config.UseHttp(httpConfig); _config.UseHttp(); _config.AddService <IWebJobsExceptionHandler>(new TestExceptionHandler()); _host = new JobHost(_config); }
public async Task ProcessRequest_MaxOutstandingRequestsExceeded_RequestsAreRejected() { int maxQueueLength = 10; Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > process = async(req, ct) => { await Task.Delay(100); return(new HttpResponseMessage(HttpStatusCode.OK)); }; var config = new HttpExtensionConfiguration { MaxOutstandingRequests = maxQueueLength, MaxConcurrentRequests = 1 }; var manager = new HttpRequestManager(config, _loggerFactory); // expect requests past the threshold to be rejected var tasks = new List <Task <HttpResponseMessage> >(); for (int i = 0; i < 25; i++) { var request = new HttpRequestMessage(); tasks.Add(manager.ProcessRequestAsync(request, process, CancellationToken.None)); } await Task.WhenAll(tasks); int countSuccess = tasks.Count(p => p.Result.StatusCode == HttpStatusCode.OK); Assert.Equal(maxQueueLength, countSuccess); int rejectCount = 25 - countSuccess; Assert.Equal(rejectCount, tasks.Count(p => p.Result.StatusCode == (HttpStatusCode)429)); IEnumerable <LogMessage> logMessages = _loggerProvider.GetAllLogMessages(); Assert.Equal(rejectCount, logMessages.Count()); Assert.True(logMessages.All(p => string.Compare("Http request queue limit of 10 has been exceeded.", p.FormattedMessage) == 0)); // send a number of requests not exceeding the limit // expect all to succeed tasks = new List <Task <HttpResponseMessage> >(); for (int i = 0; i < maxQueueLength; i++) { var request = new HttpRequestMessage(); tasks.Add(manager.ProcessRequestAsync(request, process, CancellationToken.None)); } await Task.WhenAll(tasks); Assert.True(tasks.All(p => p.Result.StatusCode == HttpStatusCode.OK)); }
/// <summary> /// Enables use of Http extensions /// </summary> /// <param name="config">The <see cref="JobHostConfiguration"/> to configure.</param> /// <param name="httpConfig">The <see cref="HttpExtensionConfiguration"/> to use.</param> public static void UseHttp(this JobHostConfiguration config, HttpExtensionConfiguration httpConfig = null) { if (config == null) { throw new ArgumentNullException("config"); } if (httpConfig == null) { httpConfig = new HttpExtensionConfiguration(); } config.RegisterExtensionConfigProvider(httpConfig); }
public async Task ProcessRequest_NoThrottle_DispatchesDirectly() { var response = new HttpResponseMessage(HttpStatusCode.OK); Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > process = (req, ct) => { return(Task.FromResult(response)); }; var config = new HttpExtensionConfiguration(); var manager = new HttpRequestManager(config, _traceWriter); var request = new HttpRequestMessage(); var result = await manager.ProcessRequestAsync(request, process, CancellationToken.None); Assert.Same(response, result); }
public async Task ProcessRequest_PropigatesExceptions() { var ex = new Exception("Kaboom!"); Func <HttpRequestMessage, CancellationToken, Task <HttpResponseMessage> > process = (req, ct) => { throw ex; }; var config = new HttpExtensionConfiguration { MaxOutstandingRequests = 10, MaxConcurrentRequests = 5 }; var manager = new HttpRequestManager(config, _traceWriter); var resultEx = await Assert.ThrowsAsync <Exception>(async() => { var request = new HttpRequestMessage(); await manager.ProcessRequestAsync(request, process, CancellationToken.None); }); Assert.Same(ex, resultEx); }
private void InitializeHttpFunctions(IEnumerable <FunctionDescriptor> functions, HttpExtensionConfiguration httpConfig) { _router.ClearRoutes(); // TODO: FACAVAL Instantiation of the ScriptRouteHandler should be cleaned up ILoggerFactory loggerFactory = _config.HostConfig.LoggerFactory; WebJobsRouteBuilder routesBuilder = _router.CreateBuilder(new ScriptRouteHandler(loggerFactory, this, _settingsManager), httpConfig.RoutePrefix); // Proxies do not honor the route prefix defined in host.json WebJobsRouteBuilder proxiesRoutesBuilder = _router.CreateBuilder(new ScriptRouteHandler(loggerFactory, this, _settingsManager), routePrefix: null); foreach (var function in functions) { var httpTrigger = function.GetTriggerAttributeOrNull <HttpTriggerAttribute>(); if (httpTrigger != null) { var constraints = new RouteValueDictionary(); if (httpTrigger.Methods != null) { constraints.Add("httpMethod", new HttpMethodRouteConstraint(httpTrigger.Methods)); } string route = httpTrigger.Route; if (string.IsNullOrEmpty(route)) { route = function.Name; } WebJobsRouteBuilder builder = function.Metadata.IsProxy ? proxiesRoutesBuilder : routesBuilder; builder.MapFunctionRoute(function.Metadata.Name, route, constraints, function.Metadata.Name); } } // Proxy routes will take precedence over http trigger functions // so they will be added first to the router. if (proxiesRoutesBuilder.Count > 0) { _router.AddFunctionRoute(proxiesRoutesBuilder.Build()); } if (routesBuilder.Count > 0) { _router.AddFunctionRoute(routesBuilder.Build()); } }
private void InitializeHttpFunctions(IEnumerable <FunctionDescriptor> functions, HttpExtensionConfiguration httpConfig) { // we must initialize the route factory here AFTER full configuration // has been resolved so we apply any route prefix customizations var functionHttpRouteFactory = new HttpRouteFactory(httpConfig.RoutePrefix); // Proxies do not honor the route prefix defined in host.json var proxyHttpRouteFactory = new HttpRouteFactory(string.Empty); _httpFunctions = new Dictionary <IHttpRoute, FunctionDescriptor>(); _httpRoutes = new HttpRouteCollection(); // Proxy routes will take precedence over http trigger functions and http trigger // routes so they will be added first to the list of http routes. var orderdFunctions = functions.OrderBy(f => f.Metadata.IsProxy ? 0 : 1); foreach (var function in orderdFunctions) { var httpTrigger = function.GetTriggerAttributeOrNull <HttpTriggerAttribute>(); if (httpTrigger != null) { IHttpRoute httpRoute = null; IEnumerable <HttpMethod> httpMethods = null; if (httpTrigger.Methods != null) { httpMethods = httpTrigger.Methods.Select(p => new HttpMethod(p)).ToArray(); } var httpRouteFactory = function.Metadata.IsProxy ? proxyHttpRouteFactory : functionHttpRouteFactory; if (httpRouteFactory.TryAddRoute(function.Metadata.Name, httpTrigger.Route, httpMethods, _httpRoutes, out httpRoute)) { _httpFunctions.Add(httpRoute, function); } } } }
private void InitializeHttpFunctions(IEnumerable <FunctionDescriptor> functions, HttpExtensionConfiguration httpConfig) { // we must initialize the route factory here AFTER full configuration // has been resolved so we apply any route prefix customizations var httpRouteFactory = new HttpRouteFactory(httpConfig.RoutePrefix); _httpFunctions = new Dictionary <IHttpRoute, FunctionDescriptor>(); _httpRoutes = new HttpRouteCollection(); foreach (var function in functions) { var httpTrigger = function.GetTriggerAttributeOrNull <HttpTriggerAttribute>(); if (httpTrigger != null) { IHttpRoute httpRoute = null; IEnumerable <HttpMethod> httpMethods = null; if (httpTrigger.Methods != null) { httpMethods = httpTrigger.Methods.Select(p => new HttpMethod(p)).ToArray(); } if (httpRouteFactory.TryAddRoute(function.Metadata.Name, httpTrigger.Route, httpMethods, _httpRoutes, out httpRoute)) { _httpFunctions.Add(httpRoute, function); } } } }
public WebScriptHostRequestManager(HttpExtensionConfiguration config, HostPerformanceManager performanceManager, IMetricsLogger metricsLogger, TraceWriter traceWriter, int performanceCheckPeriodSeconds = 15) : base(config, traceWriter) { _performanceManager = performanceManager; _metricsLogger = metricsLogger; _performanceCheckPeriodSeconds = performanceCheckPeriodSeconds; }
public TestHttpRequestManager(HttpExtensionConfiguration config, TraceWriter traceWriter, Func <bool> rejectAllRequests = null, Func <HttpRequestMessage, HttpResponseMessage> rejectRequest = null) : base(config, traceWriter) { _rejectAllRequests = rejectAllRequests; _rejectRequest = rejectRequest; }