Транзакции, синхронизация с read базой данных

Обсуждаем, как правильно строить приложения
noLogicOnlyWar
Сообщения: 83
Зарегистрирован: 2017.07.04, 20:53

Транзакции, синхронизация с read базой данных

Сообщение noLogicOnlyWar »

Добрый день. Пытаемся перевести проект на более - менее стройную архитектуру. Возник вопрос.
Суть: есть некторая AR которую хотим например удалить, после удаление должна пройти синхра с read базой данных. Для удаления есть команда. Команда выполняется в транзакции. Синхронизация должна происходить после выполнения транзакции. Хочется использовать событие ENTITY_DELETE например. Насколько знаю события публикуются в репозиториях, но беда - репозитории не используем, где лучше выталкивать событие наружу? Как бы поступили вы? Добавить еще декторатор для комманды?

Транзакционная команда:

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

class TransactionalCommand implements Command
{
    /**
     * @var Command
     */
    private $command;

    public function __construct(Command $command)
    {
        $this->command = $command;
    }

    public function execute($request = null)
    {
        $transaction = \Yii::$app->getDb()->beginTransaction();

        try {
            $this->command->execute($request);
            $transaction->commit();
        } catch (\Exception $e) {
            $transaction->rollBack();
            throw new ServiceException($e->getMessage());
        } catch (\Throwable $e) {
            $transaction->rollBack();
            throw new ServiceException($e->getMessage());
        }
    }
}
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Транзакции, синхронизация с read базой данных

Сообщение samdark »

Вы репликацию в коде делаете?
noLogicOnlyWar
Сообщения: 83
Зарегистрирован: 2017.07.04, 20:53

Re: Транзакции, синхронизация с read базой данных

Сообщение noLogicOnlyWar »

Можно и так видимо сказать, грубо говоря есть база Mysql куда пишем и база tarantool откуда читаем, в тарантуле есть хранимая процедура которую надо вызвать после того как изменили объект, соответственно вызов этот должен происходить после коммита транзакции.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Транзакции, синхронизация с read базой данных

Сообщение zelenin »

noLogicOnlyWar писал(а): 2017.10.27, 12:01Насколько знаю события публикуются в репозиториях, но беда - репозитории не используем
в любом месте где это будет целостно выглядеть. например репозиторий как единственный шлюз к хранилищу с методом delete. Вы чем удаляете? если это AR, тогда хэндлер команды.
noLogicOnlyWar
Сообщения: 83
Зарегистрирован: 2017.07.04, 20:53

Re: Транзакции, синхронизация с read базой данных

Сообщение noLogicOnlyWar »

zelenin писал(а): 2017.10.27, 13:04 в любом месте где это будет целостно выглядеть. например репозиторий как единственный шлюз к хранилищу с методом delete. Вы чем удаляете? если это AR, тогда хэндлер команды.
Для удаления есть DeleteCommand внутри удаляется через ar и делает еще какие то вещи которые совместно с удаление должны быть атомарны. Поэтому DeleteCommand оборачивается в транзакцию, а опубликовать надо вне транзакции. Поэтому как вариант - декоратор над Command который вызовет publish событий после выполнения команды?
В идеале да - хотелось бы переехать на репозитории, но слишком большая и грязная кодовая база поэтому стараемся сервисный слой выделить для начала.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Транзакции, синхронизация с read базой данных

Сообщение zelenin »

noLogicOnlyWar писал(а): 2017.10.27, 13:21
zelenin писал(а): 2017.10.27, 13:04 в любом месте где это будет целостно выглядеть. например репозиторий как единственный шлюз к хранилищу с методом delete. Вы чем удаляете? если это AR, тогда хэндлер команды.
Для удаления есть DeleteCommand
в смысле у вас самовыполняемая команда?)
noLogicOnlyWar писал(а): 2017.10.27, 13:21а опубликовать надо вне транзакции
ваша команда не знает о транзакции.
noLogicOnlyWar
Сообщения: 83
Зарегистрирован: 2017.07.04, 20:53

Re: Транзакции, синхронизация с read базой данных

Сообщение noLogicOnlyWar »

zelenin писал(а): 2017.10.27, 13:25 в смысле у вас самовыполняемая команда?)
Имелся ввиду обработчик, извиняюсь) используем термины command для обработчика и request для команды. То есть command по сути сервис для 1го юз кейса.
ваша команда не знает о транзакции.
Опять же извиняюсь за напутанную терминологию. Используем декоратор на handler'ом для того чтобы весь обработчик был в транзакции.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Транзакции, синхронизация с read базой данных

Сообщение zelenin »

noLogicOnlyWar писал(а): 2017.10.27, 13:38
zelenin писал(а): 2017.10.27, 13:25 в смысле у вас самовыполняемая команда?)
Имелся ввиду обработчик, извиняюсь) используем термины command для обработчика и request для команды.
не совсем корректно, т.к. command и есть request идеологически
noLogicOnlyWar писал(а): 2017.10.27, 13:38Опять же извиняюсь за напутанную терминологию. Используем декоратор на handler'ом для того чтобы весь обработчик был в транзакции.
хэндлер все равно не знает о декораторе. какая причина давать ему это знание, вынося событие из хэндлера?
noLogicOnlyWar
Сообщения: 83
Зарегистрирован: 2017.07.04, 20:53

Re: Транзакции, синхронизация с read базой данных

Сообщение noLogicOnlyWar »

zelenin писал(а): 2017.10.27, 13:46 хэндлер все равно не знает о декораторе. какая причина давать ему это знание, вынося событие из хэндлера?
Причина в том что обработать подобное событие (когда обработчик события обратится к read базе данных) необходимо после транзакции. То есть после того как команда обработается.

Как вариант сохранять событие я собираюсь внутри обработчика а публиковать после выполнения транзакции. Правда совсем не уверен в таком подходе.
В противном случае придется ведь использовать транзакцию внутри handler'a например, что не есть хорошо?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Транзакции, синхронизация с read базой данных

Сообщение zelenin »

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

$this->command->execute($request);
$transaction->commit();
$this->eventManager->commit();

Да, я вижу вы не только на словах перепутали команду.
$this->command->execute($request);
это традиционно должно выглядеть так: $this->handler->execute($command);
noLogicOnlyWar
Сообщения: 83
Зарегистрирован: 2017.07.04, 20:53

Re: Транзакции, синхронизация с read базой данных

Сообщение noLogicOnlyWar »

Спасибо.
zelenin писал(а): 2017.10.27, 14:14 Да, я вижу вы не только на словах перепутали команду.
Да так и есть)

Еще вопрос как тогда выглядеть будет эта ситуация когда мне не нужна транзакционность? Просто используем другой eventManager?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Транзакции, синхронизация с read базой данных

Сообщение zelenin »

noLogicOnlyWar писал(а): 2017.10.27, 14:23 Спасибо.
zelenin писал(а): 2017.10.27, 14:14 Да, я вижу вы не только на словах перепутали команду.
Да так и есть)

Еще вопрос как тогда выглядеть будет эта ситуация когда мне не нужна транзакционность? Просто используем другой eventManager?
пусть будет. У вас шина или одиночные команды? В случае шины лучше либо две мидлвари сделать с для db и event транзакций либо 2 декоратора над шиной.
noLogicOnlyWar
Сообщения: 83
Зарегистрирован: 2017.07.04, 20:53

Re: Транзакции, синхронизация с read базой данных

Сообщение noLogicOnlyWar »

Одиночные команды, используем 2 обертки над обработчиком?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Транзакции, синхронизация с read базой данных

Сообщение zelenin »

noLogicOnlyWar писал(а): 2017.10.27, 15:37 Одиночные команды, используем 2 обертки над обработчиком?
да, но удобнеее обернуть в один сервис все равно.
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: Транзакции, синхронизация с read базой данных

Сообщение anton_z »

noLogicOnlyWar писал(а): 2017.10.27, 14:02 Как вариант сохранять событие я собираюсь внутри обработчика а публиковать после выполнения транзакции. Правда совсем не уверен в таком подходе.
Все правильно придумали, в нужную сторону идете, сами так делаем, подход рабочий и очень прост. Событие сохраняется в одной транзакции с основными данными. Затем публикуется другим процессом. Так точно ничего не потеряется.

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

Для репликации из MySQL в Tarantool есть низкоуровневые решения - https://github.com/tarantool/mysql-tara ... eplication. Это все на основе libslave, который хорошо себя показал.
noLogicOnlyWar
Сообщения: 83
Зарегистрирован: 2017.07.04, 20:53

Re: Транзакции, синхронизация с read базой данных

Сообщение noLogicOnlyWar »

Спасибо за ответ
Затем публикуется другим процессом
Думаю тоже к этому прийдем, но видимо со временем.
Для репликации из MySQL в Tarantool есть низкоуровневые решения
Для нас не подходит, например создание одной записи в таблице мускуля может затронуть сразу кучу спейсов, да и тоже удаление сущности в mysql может быть soft а в тарантуле hard.

Отпишу еще 1 вопрос возникший по пути. Как писал выше сделал декоратор для обработчика который коммитит события. Соответственно надо в голове держать что все обработчики команд должны быть обернуты в этот декоратор, что конечно неудобно, тем более для нескольких программистов. Я так понимаю очевидное решение использовать шину команд + мидлвар? Почему спрашиваю - в соседней теме как раз разговор о подводных камнях шины, правда оборвался на середине.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Транзакции, синхронизация с read базой данных

Сообщение zelenin »

noLogicOnlyWar писал(а): 2017.10.30, 13:38 Спасибо за ответ
Затем публикуется другим процессом
Думаю тоже к этому прийдем, но видимо со временем.
Для репликации из MySQL в Tarantool есть низкоуровневые решения
Для нас не подходит, например создание одной записи в таблице мускуля может затронуть сразу кучу спейсов, да и тоже удаление сущности в mysql может быть soft а в тарантуле hard.

Отпишу еще 1 вопрос возникший по пути. Как писал выше сделал декоратор для обработчика который коммитит события. Соответственно надо в голове держать что все обработчики команд должны быть обернуты в этот декоратор, что конечно неудобно, тем более для нескольких программистов.
чтобы не забыть, надо куда-то инкапсулировать использование хэндлера внутри чего-то.
noLogicOnlyWar писал(а): 2017.10.30, 13:38Я так понимаю очевидное решение использовать шину команд + мидлвар? Почему спрашиваю - в соседней теме как раз разговор о подводных камнях шины, правда оборвался на середине.
шина - понятие достаточно абстрактное - туда кидаем сообщение, оттуда читаем сообщения. Детали реализации могут отличаться. Подводные камни, описанные Антоном - это скорее подводные камни канонической наивной шины из книги, чем шины реальной.
anton_z
Сообщения: 483
Зарегистрирован: 2017.01.15, 15:01

Re: Транзакции, синхронизация с read базой данных

Сообщение anton_z »

Я не о подводных камнях, а о полезности/неполезности в конкретных условиях
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Транзакции, синхронизация с read базой данных

Сообщение zelenin »

anton_z писал(а): 2017.10.30, 14:02 Я не о подводных камнях, а о полезности/неполезности в конкретных условиях
в конкретных условиях инкапсуляция сервисного слоя в одном месте с возможностью добавления общего поведения (логирование, валидация, транзакции, обработка событий), имхо, даст только плюсы. Из практики минус только один - медленнее дебажить, но это так себе.
Ответить