Использование Doctrine Entity Manager в одной базе данных в двух демонах - PullRequest
0 голосов
/ 28 июня 2018

Я запускаю два демона, которые опрашивают внешнюю службу практически каждую секунду 24/7. Каждый из них вставляет или обновляет объекты в одной и той же локальной базе данных после каждого цикла, но они работают с разными объектами одних и тех же объектов.

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

Итак, в каждом из них я запускаю что-то подобное после каждого цикла:

$this->entityManager->flush();
....
$this->entityManager->clear(MyClass:class);
$this->entityManager->clear(MyOtherClass:class);
....

Что я хочу спросить: если DaemonA очищает сущности, а DaemonB еще не сбросил сохраняющиеся изменения, что произойдет? Когда DaemonA сбрасывает, это как-то влияет на сущности в DaemonB? Могут ли некоторые объекты потеряться? Могут ли некоторые быть дублированы? Если да, что я могу сделать, чтобы избежать подобных вещей?

Как я уже сказал, они работают с разными объектами одних и тех же объектов, например, DaemonA работает с объектами MyOtherClass 1, 2, 3 и DaemonB с объектами MyOtherClass 4, 5, 6.

Оба демона являются командами Symfony, сконструированными так:

class DaemonA extends Command
{
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
        parent::__construct();
    }
    ...
 }

1 Ответ

0 голосов
/ 28 июня 2018

Здесь много вопросов, так что давайте рассмотрим их шаг за шагом.

Прежде чем мы начнем, вспомните, как Doctrine работает внутри: если сущность или набор сущностей запрашивается через запрос или репозиторий, Doctrine загружает данные сущности из базы данных, создает сущности, заполняет их данными, отслеживает изменения и синхронизирует изменения обратно в базу данных. У сущностей доктрины есть состояния , обычно они находятся в управляемом состоянии, если вы не отсоедините их. Когда вы очищаете менеджер сущностей, сущности становятся отсоединенными .

Теперь, чтобы ответить на ваши вопросы:

если DaemonA очищает сущности, а DaemonB еще не сбросил сохраненные изменения, что происходит?

Очистка менеджера сущностей означает только то, что сущности отсоединяются и, если на них больше нет ссылок, собираются в мусор (я думаю). На уровне базы данных это не имеет значения.

Когда DaemonA сбрасывает, влияет ли это каким-либо образом на объекты в DaemonB?

Да, но не во время работы DaemonB и не перезагружает сущности из базы данных. Если DaemonA изменяет сущности, а DaemonB изменяет те же сущности перед тем, как перезагружать их, модификации DaemonB сохраняются.

Могут ли некоторые быть продублированы?

Только если вы сохраните отсоединенные объекты (хотя у них будет новый идентификатор). Однако в любом случае сохранение отдельных объектов не имеет смысла.

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

Замки и транзакции!

  1. Каждая модификация вашей базы данных, которая содержит более одного запроса, должна быть включена в транзакцию. Это позволяет избежать несоответствий, если что-то идет не так или если параллельный запрос изменяет данные. На уровне PHP транзакция снова должна быть заключена в блок try / catch.

  2. Если вы изменяете сущность, заблокируйте ее. Доктрина поддерживает различные виды блокировки ; выберите тот, который подходит вашему сценарию лучше всего.

Код в одном из ваших демонов может выглядеть следующим образом:

try
{
    $em->beginTransaction();

    $entity = $em->find($entityClassName, $id);

    // lock the entity for all reading and writing. 
    $em->lock($entity, LockMode::PESSIMISTIC_WRITE);


    $em->flush();
    $em->commit();
}
catch (Exception $e)
{
    $em->rollback();

    throw $e;
}

Обратите внимание, что в зависимости от вашей стратегии блокировки и общей реализации вашей системы, демоны могут блокировать друг друга, блокируя базу данных до того момента, когда в вашей системе не хватит ресурсов.

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

Будьте внимательны и проводите тестирование в условиях большой нагрузки!

...