I have a ratchet WebSocket server, whose entityManager
is initialized from the backend. However, if some changes happen from one of the front-ends since the state of the entityManager
of the WebSocket server is different from the backend, the new changes are not reflected in the data that is served by the WebSocket server.
For this purpose, I wrote some listeners on the backend that listen for changes in these entities in and then send a request to the server like so:
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) {}
}
I then fetch the entity in the WebSocket server and simply refresh it, like so:
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);
}
}
Now here is the strange bug: The state of the $entity
that is refreshed in the WebSocket server is always one behind the real changes of the entity. Suppose I change $entity->name
from "1" to "2".
After the refresh $entity->name
is still "1" on the WebSocket server. Only if I change it again to sth else, e.g. "3", will it change to "2" (after the refresh). If I change it to "4", it will go to "3" and so on.
The event is firing correctly from the backend and the entity is being fetched correctly on the server. It's just that refresh()
works only on a second request (and therefore a second refresh) to the WebSocket server but not on the first.
I have tried even things like $entityManager->merge($entity);
but no results.
I am on symfony 3.4, doctrine 2.7, and ratchet 0.4.3.
CodePudding user response:
Doctrine uses the identity map
The websocket server is a daemon and all cleanup tasks are the responsibility of the developer
Use
\Doctrine\ORM\EntityManager::find
with the $lockMode
argument = \Doctrine\DBAL\LockMode::NONE
OR
Call the \Doctrine\ORM\EntityManager::clean
method before \Doctrine\ORM\EntityManager::find
CodePudding user response:
The first thing may be the event that is triggered to detect the update change.
If you you postPersist
the entity wont have changed in the database. It will fire before flush
happens.
You need to trigger the message to the socket server after the flush
.
The second thing is to make sure that the entityManager instance detach and reload the room
entity instance. That can be done with
$this->entityManager->getUnitOfWork()->clear(Room::class);
right before you query the entity again
$this->entityManager->getUnitOfWork()->clear(Room::class);
$room = $this->entityManager
->getRepository('ResourcesBundle:Room')
->findRoomDetailById($messageData->data->duid);