If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeAcabamos de dividir nuestro proceso de borrado de imágenes en trozos más pequeños creando una nueva clase de comando, un nuevo manejador y despachando ese nuevo comando desde el manejador Esto... técnicamente no es nada especial, pero es genial ver cómo puedes dividir cada tarea en tantos trozos como necesites.
Pero... asegurémonos de que esto realmente funciona. Todo debería seguir procesándose de forma sincronizada. Elimina la primera imagen y... actualiza para asegurarte. ¡Ya no está!
Antes de manejar la nueva clase de comandos de forma asíncrona, tenemos que pensar en algo. Si, por alguna razón, hay un problema al eliminar este ImagePost
de la base de datos, Doctrine lanzará una excepción aquí mismo y el archivo nunca se eliminará. Eso es perfecto: tanto la fila en la base de datos como el archivo en el sistema de archivos permanecerán.
Pero si el borrado de la fila de la base de datos se realiza con éxito... pero hay un problema al borrar el archivo del sistema de archivos -como un problema de conexión temporal al hablar con S3 si nuestro archivo estuviera almacenado allí-... ese archivo... en realidad... ¡nunca se borrará! Y... quizás no te importe. Pero si te importa, podrías envolver todo este bloque en una transacción Doctrine para asegurarte de que todo es correcto antes de eliminar finalmente la fila. Por supuesto... una vez que cambiemos este mensaje para que se gestione de forma asíncrona, la eliminación del archivo real se hará más tarde... y estaremos, más o menos, "confiando" en que se gestionará con éxito. Hablaremos de los fallos y reintentos muy pronto.
De todos modos, ahora que hemos dividido esto en dos partes, dirígete aconfig/packages/messenger.yaml
. Copia la línea existente, pégala y dirige la nueva DeletePhotoFile
a async
.
framework: | |
messenger: | |
... lines 3 - 12 | |
routing: | |
... lines 14 - 15 | |
'App\Message\DeletePhotoFile': async |
¡Genial! Con un poco de suerte, la fila de la base de datos se eliminará inmediatamente... y el archivo unos segundos después.
Y como acabamos de hacer un cambio en el código del manejador, vete, para nuestro trabajador y reinícialo:
php bin/console messenger:consume -vv
¡Tiempo de prueba! Refresca para estar seguro... y probemos a borrar. ¡Comprueba cuánto más rápido es! Si te acercas al terminal del trabajador... sí, está haciendo todo tipo de cosas buenas aquí. Ah, ¡y divertido! Se ha producido una excepción al manejar uno de los mensajes: no se ha encontrado un archivo. Creo que se debe a la fila duplicada causada por el error de Doctrine de hace unos minutos: el archivo ya había desaparecido cuando se eliminó la segunda imagen. Lo bueno es que ya está reintentando ese mensaje por si fuera un fallo temporal. Al final, se rinde y "rechaza" el mensaje.
¡Vamos a probar juntos este loco sistema! Sube un montón de fotos... y luego... ¡rápido! ¡Borra un par! Si te fijas en el trabajador... está todo muy mezclado: aquí se manejan unos cuantos objetos de AddPonkaToImage
... y luego DeletePhotoFile
.
Ah, y por cierto: si miras la sección routing
en messenger.yaml
, normalmente enrutarás las cosas por su nombre de clase exacto: App\Message\AddPonkaToImage
va a async
. Pero también puedes enrutar mediante interfaces o clases base. Por ejemplo, si tienes un montón de clases que deben ir al transporte async
, podrías crear tu propia interfaz -tal vez AsyncMessageInterface
-, hacer que tus mensajes la implementen, y entonces sólo tendrás que encaminar esa interfaz a async
aquí. Pero ten cuidado porque, si una clase coincide con varias líneas de enrutamiento, se enviará a todos esos transportes. Ah, y por último: en caso de que tengas un caso de uso, cada entrada de enrutamiento puede enviar a múltiples transportes.
A continuación: ¿recuerdas que el mensaje serializado en la base de datos estaba envuelto en algo llamado Envelope
? Vamos a aprender qué es eso y cómo su sistema de sellos nos da algunos superpoderes geniales.
"Houston: no signs of life"
Start the conversation!
// composer.json
{
"require": {
"php": "^7.1.3",
"ext-ctype": "*",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/annotations": "^1.0", // v1.8.0
"doctrine/doctrine-bundle": "^1.6.10", // 1.11.2
"doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // v2.0.0
"doctrine/orm": "^2.5.11", // v2.6.3
"intervention/image": "^2.4", // 2.4.2
"league/flysystem-bundle": "^1.0", // 1.1.0
"phpdocumentor/reflection-docblock": "^3.0|^4.0", // 4.3.1
"sensio/framework-extra-bundle": "^5.3", // v5.3.1
"symfony/console": "4.3.*", // v4.3.2
"symfony/dotenv": "4.3.*", // v4.3.2
"symfony/flex": "^1.9", // v1.18.7
"symfony/framework-bundle": "4.3.*", // v4.3.2
"symfony/messenger": "4.3.*", // v4.3.4
"symfony/property-access": "4.3.*", // v4.3.2
"symfony/property-info": "4.3.*", // v4.3.2
"symfony/serializer": "4.3.*", // v4.3.2
"symfony/validator": "4.3.*", // v4.3.2
"symfony/webpack-encore-bundle": "^1.5", // v1.6.2
"symfony/yaml": "4.3.*" // v4.3.2
},
"require-dev": {
"easycorp/easy-log-handler": "^1.0.7", // v1.0.7
"symfony/debug-bundle": "4.3.*", // v4.3.2
"symfony/maker-bundle": "^1.0", // v1.12.0
"symfony/monolog-bundle": "^3.0", // v3.4.0
"symfony/stopwatch": "4.3.*", // v4.3.2
"symfony/twig-bundle": "4.3.*", // v4.3.2
"symfony/var-dumper": "4.3.*", // v4.3.2
"symfony/web-profiler-bundle": "4.3.*" // v4.3.2
}
}