ServiceStack — истек тайм-аут, вызванный максимальным размером пула приложений

#servicestack #idisposable

#servicestack #idisposable

Вопрос:

Я использую funq от ServiceStack, и у меня есть код ниже в моем файле AppHost. Ошибка истечения времени ожидания API из-за превышения максимального предела размера пула приложений.

     var dbFactory = new OrmLiteConnectionFactory(string.Empty, SqlServerDialect.Provider);

... 

// Loop to get multiple different country connection string
foreach (string server in countryCodeList)
{
    dbFactory.RegisterConnection(server, connectionString, SqlServerDialect.Provider);
}

this.RequestFilters.Add((httpReq, httpRes, requestDto) =>
{
    requestInfo = requestDto.Dump();
    ...
    container.Register<IReferenceRepository>(c => new ReferenceRepository(dbFactory, baseModel.db_country_code));
    container.Register<ICompanyRepository>(c => new CompanyRepository(dbFactory, baseModel.db_country_code));
    ...
});
  

Я реализовал IDisposable в своем базовом классе репозитория. Но, похоже, он не удаляет соединение в конце каждого запроса. В perfmon.exe можно видеть, что NumberOfPooledConnections продолжает увеличиваться для каждого запроса, не удаляясь.

Коды в классе bass репозитория:

 public class Repository : IDisposable
{
    protected IDbConnectionFactory dbFactory { get; set; }
    public string CountryCode { get; set; }
    private IDbConnection db;

    public Repository(IDbConnectionFactory dbConnectionFactory, string countryCode)
    {
        this.dbFactory = dbConnectionFactory;
        this.CountryCode = countryCode;
    }

    protected virtual IDbConnection Db(string connectionKey)
    {
        return db ?? (db = dbFactory.OpenDbConnection(connectionKey));
    }

    public virtual void Dispose()
    {
        if (db != null)
            db.Dispose();
    }
}
  

Просто интересно, добавляет ли ReusedWithin(ReuseScope.Запрос) в контейнер.Регистрация части поможет ли это?

Может кто-нибудь подсказать мне, правильно ли я поступаю? Заранее спасибо.

Отредактировано: запрос API будет вызываться из одной службы в другую, и он получает данные из другого репозитория.

Комментарии:

1. (Соединения удаляются соответствующим образом, верно? Вероятно, это следует обрабатывать через связанный контейнер IoC ..)

2. @user2864740 Не совсем. Для запроса API он будет инициирован для другой службы и получит данные из другого репозитория. Не уверен, что это вызывает проблему?

Ответ №1:

Все зависимости в ServiceStack должны быть зарегистрированы, AppHost.Configure() которые выполняются один раз при запуске и после этого должны считаться неизменяемыми.

Вы не должны регистрировать зависимости в RequestFilter (который запускается при каждом запросе).

OrmLiteConnectionFactory (как и все фабрики в ServiceStack) предназначены для регистрации как одноэлементные, что также является временем жизни по умолчанию в Funq, т.е.:

 container.Register<IDbConnectionFactory>(
    c => new OrmLiteConnectionFactory(connString, SqlServerDialect.Provider));
  

Затем вы можете разрешить его из IOC, чтобы зарегистрировать свои именованные соединения, например:

 var factory=(OrmLiteConnectionFactory)container.Resolve<IDbConnectionFactory>();
foreach (string server in countryCodeList)
{
    factory.RegisterConnection(server, connString, SqlServerDialect.Provider);
}
  

Все другие зависимости, такие как ваши репозитории, также должны быть зарегистрированы AppHost.Configure() . Если он реализует IDisposable и имеет возможность повторного использования None или Request , он будет удален в конце запроса.

Использование данных запроса для создания зависимостей

Поскольку зависимости необходимо регистрировать при запуске, у него нет доступа к данным запроса. Если это то, что необходимо, его необходимо передать во время выполнения.

Вы можете уменьшить шаблон, добавив его в базовый класс обслуживания, например:

 public abstract class AppServiceBase : Service
{
    public IDbConnectionFactory DbFactory 
    { 
        get { return TryResolve<IDbConnectionFactory>(); }
    }

    ReferenceRepository refRepo;
    public ReferenceRepository ReferenceRepo
    {
        get
        {
            if (refRepo == null)
                refRepo = new ReferenceRepository(
                    DbFactory.OpenDbConnection(Request.Param("c_code")));

            return refRepo;
        }
    }

    public override Dispose()
    {
        base.Dispose();

        if (refRepo != null)
           refRepo.Dispose();
    }
}
  

К которому ваши службы могут обращаться как к обычной зависимости, т.е.:

 public class MyService : AppServiceBase
{
    public object Get(Request request)
    {
        var foo = ReferenceRepo.GetById(request.Id);
    }
}
  

Комментарии:

1. Могу ли я узнать, как получить DbFactory в классе AppServiceBase?

2. @aQing ok, да, пример обновлен. Вы можете использовать TryResolve<T> для разрешения зависимостей от класса Service. Таким же образом класс Service извлекает свою IDbConnection .

3. Развернуты коды для производства и проблема решена. Спасибо @mythz за оперативную поддержку и решение! =)