Определение объема транзакций и сеансов в NHibernate для долгосрочных задач - PullRequest
3 голосов
/ 13 апреля 2011

При использовании NHibernate в веб-приложениях я обычно позволяю своему контейнеру IoC позаботиться об открытии и закрытии ISession на запрос и фиксировать / откатить транзакцию.Природа HTTP позволяет очень легко определить четкую единицу работы в таких приложениях.

Теперь мне было поручено собрать небольшую программу, которая будет регулярно вызываться планировщиком задач,для рассылки новостей.Понятия как информационных бюллетеней, так и подписчиков уже являются четко определенными объектами в нашей модели домена, и отправка информационного бюллетеня всем подписчикам будет включать в себя нечто подобное:

var subscribers = _session
    .QueryOver<Subscription>()
    .Where(s => !s.HasReceivedNewsletter)
    .List();

foreach (var subscriber in subscribers)
{
    SendNewsletterTo(subscriber);
    subscriber.HasReceivedNewsletter = true;
}

Обратите внимание, как обновляется каждый объект Subscriberв цикле, запись, что она теперь получила информационный бюллетень.Идея состоит в том, что если программа отправки почты потерпит крах, ее можно будет перезапустить и продолжить отправку информационных бюллетеней с того места, где она остановилась.

Проблема, с которой я сталкиваюсь, заключается в определении и реализации единицы работыобразец здесь.Вероятно, мне потребуется зафиксировать изменения в базе данных к концу каждой итерации цикла.Простое обертывание тела цикла с блоком using (var trans = _session.BeginTransaction()) кажется чрезвычайно дорогим во время выполнения, и я также, похоже, испытываю проблемы с блокировкой между этим долго выполняющимся процессом и другими (веб) приложениями, использующими ту же базу данных.

Прочитав некоторые статьи и документацию по транзакциям NHibernate, я пришел к выводу, что мне может потребоваться отсоединить список подписчиков от сеанса, чтобы избежать проблем с блокировкой, и повторно присоединить каждого к новому сеансу в теле цикла.Однако я не уверен, как это будет работать для повышения производительности.

Итак, эксперты NHibernate, как бы вы спроектировали и внедрили такую ​​долгосрочную работу, как эта?

Ответы [ 3 ]

1 голос
/ 13 апреля 2011

Разве вы не хотите использовать асинхронный длительный обмен сообщениями здесь?Что-то вроде NServiceBus, Rhino Service Bus или MassTransit.Кажется, вам не нужно посылать много сообщений как можно скорее, поэтому я думаю, что вы должны делать это асинхронно с 1 продолжительным сообщением на пользователя

0 голосов
/ 13 апреля 2011

Нет проблем с несколькими транзакциями в сеансе. Здесь уместно охватить транзакцию обновлением одного подписчика, потому что это независимая операция. В зависимости от количества подписчиков и вероятности сбоя, может быть лучше одновременно захватить небольшое количество подписчиков.

foreach (var subscriber in subscribers)
{
    using (var txn = _session.BeginTransaction())
    {
        try
        {
            SendNewsletterTo(subscriber);
            subscriber.HasReceivedNewsletter = true;
            txn.Commit();
        }
        catch (Exception ex)
        {
            txn.Rollback();
            // log exception, clean up any actions SendNewsletterTo has taken if needed
            // Dispose of session and start over
        }   
    }
}
0 голосов
/ 13 апреля 2011

Не думаете ли вы, что сеанс без сохранения состояния без транзакции здесь будет лучше?

...