Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
...
try {
...
$this->executeInserts($class);
...
$this->executeUpdates($class);
...
$conn->commit();
} catch (Exception $e) {
$this->em->close();
$conn->rollback();
throw $e;
}
/*
* @throws \Doctrine\DBAL\ConnectionException If the commit failed due to no active transaction or
* because the transaction was marked for rollback only.
*/
public function commit()
{
...
if ($this->_transactionNestingLevel == 0) {
throw ConnectionException::noActiveTransaction();
}
if ($this->_isRollbackOnly) {
throw ConnectionException::commitFailedRollbackOnly();
}
...
}
$entityManagerName = 'doctrine.orm.default_entity_manager';
$page = $this->get($entityManagerName)->getRepository('AppBundle\Entity\Page')
->find(3);
$page->setText($someText);
try {
$this->get($entityManagerName)->flush($page);
} catch(\Exception $e) {
if (!$em->isOpen()) {
$this->container->get('doctrine')->resetManager($entityManagerName);
}
$page = $em->getRepository(get_class($page))->find($page->getId());
$this->get('mdiyakov_doctrine_solr.manager.index_process_manager')->reindex($page);
}
$entityManagerName = 'doctrine.orm.default_entity_manager';
$page = new AppBundle\Entity\Page();
...
$page->setText($someText);
try {
$this->get($entityManagerName)->flush($page);
} catch(\Exception $e) {
(как в примере выше)...
$this->get('mdiyakov_doctrine_solr.manager.index_process_manager')->remove($page);
}
Если при обработке события произойдет сбой, событие не отметится как обработанное и процедура повторится.
Чем это грозит? Представьте что менеджер через какую-нибудь cms тулзовину отредактировала страницу и сохранила. Она видит что сохранение успешно прошло и забывает про эту страницу. Спустя секунду запускается скрипт синхронизации с солр. Он пытается индексировать актуальную версию страницы в солр но солр говорит например что данные не валидны, превышено кол-во символов или еще что нибудь. Тогда происходит откат в базе на пред. версию. И по итогу все изменения теряются, менеджер не в курсе что это произошло и данные не обновлены. Соотв. надо реализовать уведомление о такой ситуации и тд… По итогу это все перерастает в снежний ком всякого говна. Занавес.
если солр ответит ошибкой что данные не валидны, какой смысл повторять процедуру записи в солр, надо откатывать данные в таблице page следуя определению двухфазного коммита. Но механизма роллбэка нету. И надо идти руками править данные в базе, следуя вашей логике это надо сделать и в log и в page и потом опять вызывать крон команду чтобы протолкнуть изменения в солр
Solr не реализует ACID (https://ru.wikipedia.org/wiki/ACID) да ему это и не надо соотв. какой вообще может быть разговор о двухфазном коммите скажите мне?
Да мое решение не отказустойчиво в случае внезапного отказа оборудования. Но этого и не требуется. В случае отказа оборудования вы можете просто запустить переиндексацию и все синхронизируется. В 99% случаев синхронной синхронизации реализованной в бандле достаточно.
В 99% случаев синхронной синхронизации реализованной в бандле достаточно.
Ваше решение не отказоустойчиво даже в случае обычного перезапуска веб-сервера или сервера БД, какие там отказы. После каждой перезагрузки или останова предлагаете переиндексировать?
В ваших ответах столько эмоций, зачем? Я вас пытаюсь показать лучшее решение
Если вы сервер бд стопанете у вас элементарно сайт работать не
будет.
Но тк. Solr это вторичное хранилище, вспомогательное а никак не основное то это приемлимо и решается переиндексацией.
Зачем писать индексируемые данные в отдельную таблицу log.
Теперь как можно эмулировать «двухфазный» коммит при индексации через крон. Для каждой индексируемой сущности заводите поле updated_at с DateTime когда был послдений апдейт и реализуете версионность, можно хранить всего две версии — актуальную и предыдущую (причем это касается только индексируемых в солр полей сущности). Скрипт синхронизации с солр по крону достает из базы все сущности у которых updated_at больше временной метки последней синхронизации. И для актуальной версии каждой сущности делает запрос в солр на обновление данных, если солр выкидывает эксепшн и говорит что, например, данные каким то образом не валидны то вы пишите в актуальную версию данные из предыдущей версии для сущности и удаляете предыдущую. Т.о. мы реализуем механизм роллбэка в базе в случае фейла при записи в солр.
При двухфазном коммите либо все участники выполняют транзакцию либо нет(делается rollback). У вас же база выполняет транзакцию а солр нет (читаем теорию en.wikipedia.org/wiki/Two-phase_commit_protocol). Solr не реализует ACID (https://ru.wikipedia.org/wiki/ACID) да ему это и не надо соотв. какой вообще может быть разговор о двухфазном коммите скажите мне?
А у вас «крутая библиотека», которая не является велосипедом, и которая при этом не обеспечивает отказоустойчивости?
Но как часто это случается и даже если это случилось идете и запускаете переиндексацию и всё.
DoctrineSolrBundle — поиск по Doctrine entity на базе Solr в Symfony2/3