Tengo un servidor Ratchet WebSocket, cuyo entityManager
se inicializa desde el backend. Sin embargo, si se producen algunos cambios en uno de los front-end, ya que el estado del entityManager
del servidor WebSocket es diferente al del backend, los nuevos cambios no se reflejan en los datos que proporciona el servidor WebSocket.
Para este propósito, escribí algunos oyentes en el backend que escuchan los cambios en estas entidades y luego envían una solicitud al servidor de la siguiente manera:
public function postUpdate(Room $entity, LifecycleEventArgs $_) { try { Loop::run(function() use ($entityName, $id) { $conn = yield connect('ws://localhost:8080'); yield $conn->send(json_encode(['message' => $entityName, 'data' => ['duid' => $id]])); $conn->close();}); } catch (Exception $e) {} }
Luego busco la entidad en el servidor WebSocket y simplemente la actualizo, así:
function onMessage(ConnectionInterface $from, $msg) { try { $messageData = json_decode($msg); switch ($messageData->message) { case BookingSocketActions::ROOM_CHANGED_EVENT: // $room = $this->entityManager->getRepository('ResourcesBundle:Room') // ->find(['id' => $id]); $room = $this->entityManager->getRepository('ResourcesBundle:Room') ->findRoomDetailById($messageData->data->duid); // $this->entityManager->clear(); $this->entityManager->refresh($room); break; } } catch (Exception $ex) { $from->send($ex); } }
Ahora, aquí está el error extraño: el estado de la $entity
que se actualiza en el servidor WebSocket siempre está detrás de los cambios reales de la entidad. Supongamos que cambio $entity->name
de "1" a "2".
Después de la actualización $entity->name
sigue siendo "1" en el servidor WebSocket. Solo si lo cambio de nuevo a algo más, por ejemplo, "3", cambiará a "2" (después de la actualización). Si lo cambio a "4", irá a "3" y así sucesivamente.
El evento se activa correctamente desde el backend y la entidad se recupera correctamente en el servidor. Es solo que refresh()
funciona solo en una segunda solicitud (y, por lo tanto, una segunda actualización) al servidor WebSocket, pero no en la primera.
He intentado incluso cosas como $entityManager->merge($entity);
pero sin resultados.
Estoy en Symfony 3.4, Doctrine 2.7 y Ratchet 0.4.3.
Lo primero puede ser el evento que se dispara para detectar el cambio de actualización.
Si postPersist
, la entidad no habrá cambiado en la base de datos. Se disparará antes de que ocurra la flush
.
Debe enviar el mensaje al servidor de socket después del flush
.
Lo segundo es asegurarse de que la instancia de entityManager desconecte y vuelva a cargar la instancia de entidad de room
. Eso se puede hacer con
$this->entityManager->getUnitOfWork()->clear(Room::class);
justo antes de volver a consultar la entidad
$this->entityManager->getUnitOfWork()->clear(Room::class); $room = $this->entityManager ->getRepository('ResourcesBundle:Room') ->findRoomDetailById($messageData->data->duid);
Doctrine usa el mapa de identidad
El servidor websocket es un demonio y todas las tareas de limpieza son responsabilidad del desarrollador.
Usar
\Doctrine\ORM\EntityManager::find
con el argumento $lockMode
= \Doctrine\DBAL\LockMode::NONE
O
Llame al método \Doctrine\ORM\EntityManager::clean
antes de \Doctrine\ORM\EntityManager::find