Probleme bei der Verwendung von Doctrine ODM in Daemon-Prozessen

Ich möchte über meine Erfahrungen mit Doctrine ODM in einem relativ kleinen PHP-Projekt sprechen, in dem sich die Hauptcodebasis auf Daemon-Prozesse konzentriert. Und im Allgemeinen, wie wir Doctrine ODM an Yii2 befestigt haben. Ich warne Sie sofort - die Geschichte wird sehr langweilig und höchstwahrscheinlich nur für diejenigen interessant sein, die bereits auf Probleme bei der Arbeit mit Doctrine ODM in Daemon-Prozessen gestoßen sind.


Wo wir schrauben werden


Vor ungefähr 6 Jahren haben sie mich mit der Aufgabe betraut: von einem Monolithen in einen Yii1Code in einen separaten Dienst zu schneiden . Gesagt, getan. Das Framework hat sich lange Zeit nicht entschieden, außer Yiiich wusste nichts, und dann kündigten sie eine bevorstehende Veröffentlichung an Yii2, die zu dieser Zeit sehr stilvoll / modisch / jugendlich schien, aber die Kenntnis der ersten Version dieses Frameworks ermöglichte es uns, den Schwellenwert für die Eingabe der zweiten Version zu senken. MongoDB war ebenfalls in Mode, mit dem wir bereits vertraut waren und Yii1mit einer separaten Erweiterung arbeiteten, die jedoch Yii2sofort unterstützt wurde.


Anfänglich war der Microservice recht einfach: Es war erforderlich, Dateien von Benutzern zu empfangen und in einem dauerhaften Speicher zu speichern, Aufzeichnungen dieser Dateien in der Datenbank zu führen, Informationen zu diesen Dateien und Links zu ihnen als Antwort auf relevante Anforderungen über die API auszugeben.


Im Laufe der Zeit begann dieser Mikrodienst zu wachsen: Videoverarbeitung, Virenprüfung, verteilte Speicherung über verschiedene Regionen (a la CDN) erschienen. Die Zeit verging schnell, das Projekt entwickelte sich aktiv und wurde sogar umgestaltet, aber irgendwann trat aufgrund neuer Trends und auch des beruflichen Wachstums ein Gefühl von Unbehagen bei der Interaktion mit diesem Projekt auf. Der Wunsch, an diesem Projekt zu arbeiten, wurde immer geringer und ich dachte ernsthaft nach.


Embedded Document . , PHP . , , , . , , . , .


PHP 7- , . ActiveRecord Yii2 — "" , , phpdoc. MongoDB, - , - {user_id : '12'}


, . - , Yii2 . , , , , , .



, , MongoDB.
Symfony Doctrine ORM, Doctrine ODMORM MongoDB.


Yii2 Symfony , , :
- — , , .
- — ActiveRecord " " Yii2


, ActiveRecord Doctrine ODM, . , ORM .


. Doctrine DocumentManager ( EntityManager Doctrine ORM). " ".


Dependency Injection Container Yii2 , .


Yii2 DataProvider'a. -, CRUD- . " " . , Yii2. , , — , .


, Doctrine UnitOfWork , .



, : DI- , . - , Symfony .


, :


while (!$this->isShuttingDown()) {
    //  Task,  ,     
    //  MANAGED    ,
    //     
    $task = $this->taskProvider->getNextTask();
    try {
        //   -  , ,  
        $this->someService->runTask($task);
    } catch (SomeException $e) {
        //    :       
        //     MANAGED,      
        //       -     
        $this->switchTaskToError($task, $e);
    }
}

, - dirty ( flush() ), , , .


clear() "" . , , . clear() , , , $this->someService->runTask($task);



, ( , — ), . . , , . , , . .


:


while (!$this->isShuttingDown()) {
    //  ,  , 
    //   -  ,   
    //    detached,      , 
    //      
    $task = $this->taskProvider->getNextTask();
    try {
        //   -     
        $this->someService->runTask($task);
    } catch (SomeException $e) {
        //    ,  -   
        $this->switchTaskToError($task, $e);
    }
}

taskProvider someService , .


merge. runTask() :


public function runTask(Task $task) {
    $dm = $thic->dmFactory->createDocumentManager();
    $task = $dm->merge($task);
    ....
    $task->setStatus(Task::STATUS_OK);
    $dm->flush();
}

switchTaskToError() :


public function switchTaskToError(Task $task, Throwable $) {
    $dm = $this->dmFactory->createDocumentManager();
    $task = $dm->merge($task);
    $task->setStatus(Task::STATUS_ERROR);
    $task->setError($e->getMessage());
    $dm->flush();
}

, $dm .


, , - . , :


$tasks = $this->taskProvider->getProblemTasks();
$dm = $thic->dmFactory->createDocumentManager();
foreach ($tasks as $task) {
     $task = $dm->merge($task);
     $task->setState(..);
}
$dm->flush();

getProblemTasks , , "" , Task merge(). , merge() — .. , .


, , :


$dm = $thic->dmFactory->createDocumentManager();
$tasks = $this->taskProvider->getProblemTasks($dm);
foreach ($tasks as $task) {
     $task->setState(..);
}
$dm->flush();

.


JPA


, Doctrine JPA: , UnitOfWork, (managed, detached ..). JPA , , . , — . (Spring Framework ). JPA , , .


, , . - , , - (? ), ( ). , , .


, hibernate Doctrine.


Doctrine ODM


" doctrine" , - http , , , .


, . , . . , :


$session = $this->sessionManager->createNewSession();
try {
    $dm= $session->getDocumentManager();
    $tasks = $this->taskProvider->getProblemTasks();
    foreach ($tasks as $task) {
        $task->setState(..);
    }
    $dm->flush();
} finally {
    $this->sessionManager->close($session);
}

getProblemTasks


public function getProblemTasks(): array
{
    $repo = $this->sessionManager
                      ->getCurrentSession()
                      ->getDocumentManager()
                      ->getRepository(Task::class);

    return $repo->findBy(['status' => Task::STATUS_ERROR]);
}

, , , , .


:


public function switchTaskToError(Task $task, Throwable $) {
    //   ,  ,    
    $session $this->sessionManager->createNewSession();
    $dm = $session->getDocumentManager();
    try {
        $task = $dm->merge($task);
        $task->setStatus(Task::STATUS_ERROR);
        $task->setError($e->getMessage());
        $dm->flush();
    finally {
        $this->sessionManager->close($session);
    }
}

, , , wrap, , .


, 3 SessionManager


createNewSession — , "" .
getCurrentSession — .
close


, ( php-ds).


:
createNewSession — , .
getCurrentSession — , , .
close — .


, , , .


wrap, , :


public function switchTaskToError(Task $task, Throwable $) {
    $this->sessionManager->wrapBySession(function(DocumentManager $dm) use ($task, $e) {
        $task = $dm->merge($task);
        $task->setStatus(Task::STATUS_ERROR);
        $task->setError($e->getMessage());
        $dm->flush();
    });
}


Im Allgemeinen erwies sich der Sitzungsmechanismus als recht praktisch. Zumindest hat er alle unsere Probleme gelöst. Natürlich wäre es schön, Sitzungen auch mit einem deklarativen Ansatz zu verwalten, wie dies beispielsweise im Spring Framework der Fall ist. Dies würde den Overhead in Form von redundantem Code erheblich reduzieren, aber im Moment kann ich mir nicht einmal vorstellen, wie dies in PHP gemacht werden kann.


All Articles