Веб-сервер Owin Selffhost медленно отвечает, когда в приложении запущено несколько потоков - PullRequest
4 голосов
/ 13 марта 2019

У меня странная проблема с отзывчивостью веб-сервера автономного хоста owin в ситуации, когда приложение запускает несколько потоков.

Я привел простой пример, демонстрирующий проблему:

  • Веб-сервер запускается
  • Аппликация запускается 150 (фиктивные потоки)
  • , если вы попытаетесь позвонить http://localhost:5000/api/administration/getAllSmtpSettings
  • , вы не получите ответ в течение 30-40 секунд
  • Загрузка процессора обычно составляет 7-10%

Код приложения:

using System;
using System.Threading;
using System.Threading.Tasks;
using Test.Api;

namespace Test.Web
{
    class Program
    {
        public static void RunWebServer()
        {
            Task.Factory.StartNew(() =>
            {
                StartWebServer();

            }, TaskCreationOptions.LongRunning);
        }

        private static void StartWebServer()
        {
            WebServer.StartWebServer();

            while (true)
            {
                Thread.Sleep(10);
            }
        }

        private static void StartThreads(int maxthreads)
        {
            for (int m = 0; m < maxthreads; m++)
            {
                Task.Factory.StartNew(() =>
                {
                    while (true)
                    {
                        Thread.Sleep(1000);
                    }
                });

                Thread.Sleep(10);
            }
        }

        static void Main(string[] args)
        {
            RunWebServer();
            StartThreads(150);
            Console.ReadKey();
        }
    }
}

Код веб-сервера:

using Microsoft.Owin.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Ninject;
using Ninject.Web.Common;
using Ninject.Web.Common.OwinHost;
using Ninject.Web.WebApi.OwinHost;
using Owin;
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Reflection;
using System.Web.Http;

namespace Test.Api
{
    //************************************WEB SERVER*************************************
    public class RouteConfig
    {
        public static HttpConfiguration RegisterRoutes()
        {
            var config = new HttpConfiguration();

            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            return config;
        }
    }

    public static class NinjectConfig
    {
        public static Lazy<IKernel> CreateKernel = new Lazy<IKernel>(() =>
        {
            var kernel = new StandardKernel();
            kernel.Load(Assembly.GetExecutingAssembly());
            RegisterServices(kernel);

            return kernel;
        });

        private static void RegisterServices(KernelBase kernel)
        {
            kernel.Bind<IAdministrationManager>().To<AdministrationManager>().InRequestScope();
        }
    }

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {

            var config = RouteConfig.RegisterRoutes();

            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

            // Add Ninject middleware
            app.UseNinjectMiddleware(() => NinjectConfig.CreateKernel.Value);
            app.UseNinjectWebApi(config);

            // Use JSON formater
            config.Formatters.Clear();
            config.Formatters.Add(new JsonMediaTypeFormatter());
            config.Formatters.JsonFormatter.SerializerSettings =
            new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };

            config.Formatters.JsonFormatter.SerializerSettings.Converters
            .Add(new StringEnumConverter());

            //app.UseWebApi(config);
        }
    }

    public class WebServer
    {
        private static IDisposable _webApplication = null;

        public static void StartWebServer()
        {
            try
            {
                var webPort   = 5000;
                var httpHost = "localhost";

                StartOptions options = new StartOptions();

                options.Urls.Add($"http://{httpHost}:{webPort}");
                Console.WriteLine($"Url used  http://{httpHost}:{webPort}");

                _webApplication = WebApp.Start<Startup>(options);
                Console.WriteLine("Web server successfully started");

            }
            catch(Exception)
            {

            }
        }
    }

    //************************************MANAGERS*************************************
    public interface IAdministrationManager
    {
        string GetAllSmtpSettings();
    }

    public class AdministrationManager : IAdministrationManager
    {
        public string GetAllSmtpSettings()
        {
            Console.WriteLine("Response");
            return "JESSSSSSSSSSSSSSS" + Guid.NewGuid().ToString();
        }

    }

    //************************************Controllers*************************************

    [RoutePrefix("api/administration")]
    public class AdministrationController : ApiController
    {
        IAdministrationManager _mng = null;
        public AdministrationController(IAdministrationManager mng)
        {
            _mng = mng;
        }

        [HttpGet]
        [Route("getAllSmtpSettings")]
        public HttpResponseMessage GetAllSmtpSettings()
        {
            var result = _mng.GetAllSmtpSettings();
            Console.WriteLine("Response created");

            return Request.CreateResponse(HttpStatusCode.OK, result);
        }

    }
}

Используемые пакеты:

    <?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Castle.Core" version="4.3.1" targetFramework="net471" />
  <package id="LimitsMiddleware" version="3.2.0" targetFramework="net471" />
  <package id="LimitsMiddleware.OwinAppBuilder" version="3.2.0" targetFramework="net471" />
  <package id="Microsoft.AspNet.Cors" version="5.2.7" targetFramework="net471" />
  <package id="Microsoft.AspNet.Identity.Core" version="2.2.2" targetFramework="net471" />
  <package id="Microsoft.AspNet.Identity.Owin" version="2.2.2" targetFramework="net471" />
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.7" targetFramework="net471" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.7" targetFramework="net471" />
  <package id="Microsoft.AspNet.WebApi.Owin" version="5.2.7" targetFramework="net471" />
  <package id="Microsoft.AspNet.WebApi.OwinSelfHost" version="5.2.7" targetFramework="net471" />
  <package id="Microsoft.Owin" version="4.0.1" targetFramework="net471" />
  <package id="Microsoft.Owin.Cors" version="4.0.1" targetFramework="net471" />
  <package id="Microsoft.Owin.Diagnostics" version="4.0.1" targetFramework="net471" />
  <package id="Microsoft.Owin.FileSystems" version="4.0.1" targetFramework="net471" />
  <package id="Microsoft.Owin.Host.HttpListener" version="4.0.1" targetFramework="net471" />
  <package id="Microsoft.Owin.Hosting" version="4.0.1" targetFramework="net471" />
  <package id="Microsoft.Owin.Security" version="4.0.1" targetFramework="net471" />
  <package id="Microsoft.Owin.Security.Cookies" version="4.0.1" targetFramework="net471" />
  <package id="Microsoft.Owin.Security.OAuth" version="4.0.1" targetFramework="net471" />
  <package id="Microsoft.Owin.StaticFiles" version="4.0.1" targetFramework="net471" />
  <package id="Newtonsoft.Json" version="11.0.2" targetFramework="net471" />
  <package id="Ninject" version="3.3.4" targetFramework="net471" />
  <package id="Ninject.Extensions.ContextPreservation" version="3.3.1" targetFramework="net471" />
  <package id="Ninject.Extensions.Factory" version="3.3.2" targetFramework="net471" />
  <package id="Ninject.Extensions.NamedScope" version="3.3.0" targetFramework="net471" />
  <package id="Ninject.Web.Common" version="3.3.1" targetFramework="net471" />
  <package id="Ninject.Web.Common.OwinHost" version="3.3.1" targetFramework="net471" />
  <package id="Ninject.Web.WebApi" version="3.3.0" targetFramework="net471" />
  <package id="Ninject.Web.WebApi.OwinHost" version="3.3.0" targetFramework="net471" />
  <package id="Owin" version="1.0" targetFramework="net471" />
  <package id="Owin.Limits" version="1.0.1.0" targetFramework="net471" />
</packages>

Я пытался настроить приоритетность для сервера, на котором запущен Thread, но это не помогает.Через несколько первых 30-40 секунд веб-сервер начинает правильно отвечать.

Заранее благодарен за любую помощь или предложение.

...