Masalah Menggunakan Doctrine ODM dalam Proses Daemon

Saya ingin berbicara tentang pengalaman saya menggunakan Doctrine ODM dalam proyek PHP yang relatif kecil di mana basis kode utama terkonsentrasi dalam proses daemon. Dan secara umum, bagaimana kami mengikatkan Doktrin ODM ke Yii2. Saya memperingatkan Anda segera - ceritanya akan sangat membosankan dan kemungkinan besar hanya menarik bagi mereka yang telah mengalami masalah ketika bekerja dengan Doctrine ODM dalam proses daemon.


Di mana kita akan sekrup


Sekitar 6 tahun yang lalu, mereka mempercayakan saya pada tugas: untuk memotong dari satu monolith menjadi Yii1sepotong kode menjadi layanan terpisah. Tidak lebih cepat dikatakan daripada dilakukan. Kerangka kerja ini tidak memilih untuk waktu yang lama, kecuali Yiisaya tidak tahu apa-apa, dan kemudian mereka mengumumkan rilis segera Yii2, yang pada saat itu tampak sangat bergaya / modis / muda, tetapi pengetahuan tentang versi pertama dari kerangka kerja ini memungkinkan mengurangi ambang batas untuk memasuki versi kedua. MongoDB juga fashionable, yang dengannya kami sudah terbiasa dan bekerja Yii1dengan ekstensi yang terpisah, tetapi Yii2didukung di luar kotak.


Pada awalnya, layanan Microsoft cukup sederhana: perlu untuk menerima file dari pengguna dan menyimpannya dalam penyimpanan yang persisten, menyimpan catatan file-file ini dalam database, mengeluarkan informasi mengenai file-file ini dan menghubungkannya dengan mereka dalam menanggapi permintaan yang relevan melalui API.


Seiring waktu, layanan mikro ini mulai tumbuh: pemrosesan video, pemindaian virus, dan penyimpanan terdistribusi di berbagai wilayah muncul (a la CDN). Waktu berlalu dengan cepat, proyek berkembang secara aktif dan bahkan menjalani refactoring, tetapi pada beberapa titik, karena tren baru dan pertumbuhan profesional, juga, perasaan tidak nyaman muncul ketika berinteraksi dengan proyek ini. Keinginan untuk mengerjakan proyek ini menjadi semakin berkurang dan saya berpikir dengan serius.


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


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


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



, , MongoDB.
Symfony Doctrine ORM, Doctrine ODM — ORM 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();
    });
}


Secara umum, mekanisme sesi ternyata cukup nyaman. Setidaknya dia menyelesaikan semua masalah kita. Tentu saja, akan menyenangkan juga mengelola sesi menggunakan pendekatan deklaratif, seperti yang dilakukan dalam Kerangka Kerja Spring, misalnya. Ini secara signifikan akan mengurangi overhead dalam bentuk kode redundan, tetapi saat ini saya bahkan tidak bisa membayangkan bagaimana hal ini dapat dilakukan dalam PHP.


All Articles