У меня есть пара циклов, каждый из которых порождает асинхронные процессы через ConcurrentQueue<T>
.Эти процессы вызывают некоторые реализации бизнес-сервисов, которые используют хранилище для взаимодействия с базой данных.Все реализации сервиса подключены через StructureMap.
Реализация репозитория имеет некоторые характеристики, которые требуют тщательного управления:
- Используемая технология базы данных: Redis .
- Реализация использует Redis-клиент ServiceStack.net (через
PooledRedisClientManager
). - Несколько методов используют транзакции, которые (я считаю) не могут быть созданы одновременно одним и тем же RedisClient.Поэтому совместное использование одной реализации репозитория для нескольких асинхронных процессов невозможно, так как при этом будет пытаться создать несколько транзакций одновременно.
- Чтобы освободить подключения к памяти и базе данных, эти объекты должны быть явно расположены - как таковые, яреализовал IDisposable в классе репозитория.
- Нет никаких причин, по которым экземпляр репозитория не может совместно использоваться в пределах области действия отдельного асинхронного процесса, поскольку существуетне будет одновременных запросов / транзакций.
Учитывая вышесказанное, я бы хотел привязать один экземпляр репозитория к времени жизни каждого асинхронного процесса.
Одна вещь дляимейте в виду, что службы, используемые с областью асинхронных процессов, также используются другими частями системы, которые имеют различные характеристики времени жизни (например, на веб-сайте, где хранилище ограничено временем жизни запроса страницы).
Я будупопробуйте проиллюстрировать это некоторым кодом (упрощенно из моего кода):
Программа, управляющая очередью (и подключающая обработчик событий, который выполняет вызов IAsyncResult
):
public class Program
{
private readonly ConcurrentQueue<QueueItem> queue = new ConcurrentQueue<QueueItem>();
private readonly IItemManager itemManager; // implemented via constructor DI.
public void ProcessQueueItems()
{
while ( queue.Count > 0 || shouldContinueEnqueuing )
{
QueueItem item;
if ( queue.TryDequeue( out item ) )
{
// Begin async process here - only one repository should be used within the scope of this invocation
// (i.e. withing the scope of the itemManager.ProcessItem( item ) method call.
new ItemProcessor( itemMananger.ProcessItem ).BeginInvoke( e.Item, ItemCallback, null );
}
Thread.Sleep( 1 );
}
}
private static void ItemCallback( IAsyncResult result )
{
var asyncResult = ( AsyncResult ) result;
var caller = ( ItemProcessor ) asyncResult.AsyncDelegate;
var outcome = caller.EndInvoke( result );
// Do something with outcome...
}
private delegate ItemResult ItemProcessor( QueueItem item );
}
Реализациякоторый вызывается асинхронным результатом.Я хочу управлять областью действия в методе ProcessItem( ... )
:
public class ItemManager : IItemManager
{
private readonly IServiceA serviceA; // implemented via constructor DI.
private readonly IServiceB serviceB; // implemented via constructor DI.
public ItemResult ProcessItem( QueueItem item )
{
// Both serviceA and serviceB use the repository which is injected via StructureMap. They should share
// the instance and at the end of the process it should be disposed (manually, if needs be).
var something = serviceA.DoSomething( item );
return serviceB.GetResult( something );
}
}
Я думаю, что это объясняет ситуацию и цели.У меня следующие вопросы:
- Могу ли я использовать StructureMap для использования другой области действия в контексте одного процесса, как описано выше.
- Я не хочу включать прямойзависимость для StructureMap в моем доменном / сервисном слое.Итак, если на этом этапе я могу использовать другую область видимости, есть ли простой способ сделать это без непосредственного вызова StructureMap из самого процесса?
- Могу ли я дать через StructureLap через конфигурацию DSL распоряжение утилизироватьхранилище в конце процесса или мне нужно явно сделать это в моем коде?