DDD и транзакции

Обсуждаем, как правильно строить приложения
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

DDD и транзакции

Сообщение anton_z »

Уважаемые члены сообщества, помогите внести ясность в вопрос.
Имею шину команд. Нужно обеспечить транзакционность. Видел решения https://php-and-symfony.matthiasnoback. ... mmand-bus/ связанные и использованием перехватов, шина декорируется классом, где разруливается транзакция. Т.е. обработчики команд ничего не знают о транзакции.

Таким образом, если написать обработчик, который будет работать с БД, а еще отправлять письмо (делать что-то нетранзакционное) прямо или косвенно (через события), то возникает окно для несогласованности - письмо отправлено, транзакция откатилась.

Будет ли перенос управления транзакцией в обработчик команды, более правильным решением в данном случае? Не является ли вынос управления транзакцией в декоратор плохой практикой? Или все совсем наоборот и транзация является сквозным аспектом приложения и ей именно так и нужно управлять? Лично мне думается, что в этом случае появляется тесная связь между декоратором и обработчиками, использующими БД.

P.S. Полгода не заходил на форум..Очень радует, что появилось большое количество обсуждений архитектуры приложений и DDD. Сообщество растет качественно). Может и фреймворк в ответ на меняющиеся условия станет менее монолитным?) (риторический вопрос) Уж не осудите за оффтоп).

Аватара пользователя
samdark
Администратор
Сообщения: 9355
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: DDD и транзакции

Сообщение samdark »

А почему не отправлять письмо только в случае успешного завершения транзакции?

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DDD и транзакции

Сообщение zelenin »

samdark писал(а):
2017.01.15, 17:29
А почему не отправлять письмо только в случае успешного завершения транзакции?
потому что транзакция в предлагаемом декораторе выше по уровню оригинального хэндлера - хэндлер не знает о транзакции.

anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: DDD и транзакции

Сообщение anton_z »

zelenin писал(а):
2017.01.15, 17:36
samdark писал(а):
2017.01.15, 17:29
А почему не отправлять письмо только в случае успешного завершения транзакции?
потому что транзакция в предлагаемом декораторе выше по уровню оригинального хэндлера - хэндлер не знает о транзакции.
Верно подмечено.

Аватара пользователя
samdark
Администратор
Сообщения: 9355
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: DDD и транзакции

Сообщение samdark »

В хендлере нельзя триггернуть событие вроде "успех" и на него зацепиться чем-то ещё?

Аватара пользователя
ElisDN
Сообщения: 5598
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DDD и транзакции

Сообщение ElisDN »

В таких случаях декорирую и EventDispatcher, чтобы его метод dispatch в приватный массив все события сохранял. И после коммита в шине вызываю запуск обработки.

anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: DDD и транзакции

Сообщение anton_z »

samdark писал(а):
2017.01.15, 18:27
В хендлере нельзя триггернуть событие вроде "успех" и на него зацепиться чем-то ещё?
Так и делаю, но проблему транзакции это не решает, Обработчик события, который будет отправлять почту, тем более не знает, завершилась транзакция или нет.

anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: DDD и транзакции

Сообщение anton_z »

ElisDN писал(а):
2017.01.15, 20:16
В таких случаях декорирую и EventDispatcher, чтобы его метод dispatch в приватный массив все события сохранял. И после коммита в шине вызываю запуск обработки.
Т.е. декторатор шины команд, в котором обрабатывается транзакция, управляет шиной событий, верно?
Получается когда ввожу транзакции в приложение, должен буду сделать два декоратора - на шину команд и шину событий и из первого управлять вторым. В командах ничего нетранзакционного напрямую получается делать нельзя, только через шину событий. Все равно какая-то связь в виде умолчания (то, что нельзя ничего нетранзакционного делать в обработчике) остается. Компромиссное решение.

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

Аватара пользователя
ElisDN
Сообщения: 5598
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DDD и транзакции

Сообщение ElisDN »

anton_z писал(а):
2017.01.16, 05:20
Т.е. декторатор шины команд, в котором обрабатывается транзакция, управляет шиной событий, верно?
Получается когда ввожу транзакции в приложение, должен буду сделать два декоратора - на шину команд и шину событий и из первого управлять вторым.
Верно:

Код: Выделить всё

class TransactionalCommandBus implements CommandBusInterface
{
    public function construct(
        CommandBusInterface $next,
        DeferredEventDispatcher $dispatcher,
        Transtaction $transaction
    ) { ... }

    public function handle($command) {
        $this->transaction->execute(function () use ($command) {
            call_user_func($this->next, $command);
            // $this->em->flush();
        });
        $this->dispatcher->handleDeferredEvents();
    }
}
anton_z писал(а):
2017.01.16, 05:20
Не лучше ли управлять транзакциями в обработчике команды? Чем это хуже перехвата?
Управляйте:

Код: Выделить всё

public function handle(MyCommand $command)
{
    $entity1 = new Entity1(...);
    $entity2 = new Entity2(...);
    $this->transactionManager->execute(function () use ($entity1, $entity2) {
        $this->repository1->add($entity1);
        $this->repository2->add($entity2);
    });
    $this->eventDispatcher->dispatch(...);
}
Лучше тем, что:

- можно явно запускать нетранзакционные операции (хотя им всё равно, в сервисе их запускают или по событию).

Хуже тем, что:

- в сервис просочилось знание о транзакциях;
- теперь нужно запускать UnitOfWork::flush() в каждом репозитории, а не один раз с транзакцией в шине.
Последний раз редактировалось ElisDN 2017.04.26, 17:10, всего редактировалось 6 раз.

Аватара пользователя
samdark
Администратор
Сообщения: 9355
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: DDD и транзакции

Сообщение samdark »

Так и делаю, но проблему транзакции это не решает, Обработчик события, который будет отправлять почту, тем более не знает, завершилась транзакция или нет.
Кажется, пример плохой... Событие на отправку почты мы триггерим только в том случае, если успешно отработала первая часть и не триггерим в противном случае. В нашем случае фейл отправки почты не означает отката изменений базы, что значит что по сути это не транзакция, а последовательность действий.

anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: DDD и транзакции

Сообщение anton_z »

samdark писал(а):
2017.01.16, 11:10
Так и делаю, но проблему транзакции это не решает, Обработчик события, который будет отправлять почту, тем более не знает, завершилась транзакция или нет.
Кажется, пример плохой... Событие на отправку почты мы триггерим только в том случае, если успешно отработала первая часть и не триггерим в противном случае. В нашем случае фейл отправки почты не означает отката изменений базы, что значит что по сути это не транзакция, а последовательность действий.
Отправку почты взял чтобы не было ни у кого желания предлагать обработать нетранзакционную операцию, например сохранение файла куда-то.

anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: DDD и транзакции

Сообщение anton_z »

ElisDN писал(а):
2017.01.16, 10:21
Лучше тем, что:

- можно явно запускать нетранзакционные операции (хотя им всё равно, в сервисе их запускают или по событию).
Тут еще устраняется тесная связь между декоратором, в котором управляется транзакция и обработчиком, разве нет?

Например, когда я пишу обработчик, я же не знаю, что у меня там за шина будет. Обрабатывает она транзакции или нет. Если буду опираться на то, что обрабатывает - получу тесную связь, не так ли?

Аватара пользователя
ElisDN
Сообщения: 5598
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DDD и транзакции

Сообщение ElisDN »

anton_z писал(а):
2017.01.16, 12:36
Если буду опираться на то, что обрабатывает - получу тесную связь, не так ли?
Это и имеется в виду в пункте "в сервис просочилось знание о транзакциях".

Аватара пользователя
samdark
Администратор
Сообщения: 9355
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: DDD и транзакции

Сообщение samdark »

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

anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: DDD и транзакции

Сообщение anton_z »

samdark писал(а):
2017.01.16, 11:10
Так и делаю, но проблему транзакции это не решает, Обработчик события, который будет отправлять почту, тем более не знает, завершилась транзакция или нет.
Кажется, пример плохой... Событие на отправку почты мы триггерим только в том случае, если успешно отработала первая часть и не триггерим в противном случае. В нашем случае фейл отправки почты не означает отката изменений базы, что значит что по сути это не транзакция, а последовательность действий.
Вопрос как раз в том, как правильно соблюсти эту последовательность при использовании шины команд с транзакциями.

Аватара пользователя
samdark
Администратор
Сообщения: 9355
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: DDD и транзакции

Сообщение samdark »

Нельзя для примера с транзакциями рассматривать заведомо не транзакционные части операции, такие как отсылка почты. Это путает. Чтобы у нас вышла нормальная транзакция придётся реализовать что-то типа two-phase commit protocol на уровне шины. А для этого отсылку почты (или как минимум её постановку в очередь) нужно иметь возможность откатить.

anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: DDD и транзакции

Сообщение anton_z »

Я знаю что такое 2PC. Мне нужно было узнать, как правильно работать на шине с транзакциями с учетом того, что в обработчиках могут быть заведомо нетранзакционные операции.

Вы хотите сказать, что шину надо либо делать полностью транзакционной (все хендлеры можно откатить), либо вообще не рулить транзакциями в декораторе шины?

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DDD и транзакции

Сообщение zelenin »

да никак. Нельзя работать с нетранзакционными операциями без знания ими о транзакциях. Поэтому транзакции делают уровнем ниже - в репозиториях - транзакционно сохраняя агрегат в Repository::save(...). Оборачивание же шины в транзакцию некорректно, т.к. внутри хэндлера происходят действия разных слоев.

anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: DDD и транзакции

Сообщение anton_z »

Про правило одного агрегата слышал. А как же быть со всякими групповыми операциями, охватывающими более одного агрегата? Например, сразу отменить 10 заказов - пользователь отмечает галочками и жмакает на кнопку.

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DDD и транзакции

Сообщение zelenin »

anton_z писал(а):
2017.01.16, 15:52
Про правило одного агрегата слышал. А как же быть со всякими групповыми операциями, охватывающими более одного агрегата? Например, сразу отменить 10 заказов - пользователь отмечает галочками и жмакает на кнопку.
этот пример не требует атомарности.

Ответить