Ir al contenido principal
Laravel, shipping fast.

Una trampa que al principio parece buena noticia: etiquetar una versión nueva del paquete no llega automáticamente a ni un solo sitio de cliente. Nada cambia en ninguna instancia ya aprovisionada en el momento en que publicas una etiqueta.

Eso es deliberado, no una carencia. Si publicar una versión mutara al instante todos los sitios activos, una mala versión tumbaría la flota entera a la vez, sin despliegue gradual, sin canario. El aislamiento es el mecanismo de seguridad, pero viene con una obligación: llegar a una instancia activa son dos pasos explícitos, y ambos tienen que ocurrir, o «he publicado el arreglo» y «todos los clientes tienen el arreglo» dejan calladamente de ser el mismo hecho.

tag webplo/templates v1.1.85
bump the version constraint in the skeleton's composer.json
redeploy that instance (or run the installer again on it)
webplo:install re-bakes the theme + editable system on disk

Etiqueta una versión nueva y la restricción ya está satisfecha sobre el papel, pero nada la instala hasta que algo ejecuta una actualización y redespliega. En una flota donde cada instancia de cliente es su propio repositorio, ese segundo paso es fácil de perder de vista: etiquetas la versión, escribes la entrada del changelog y sigues adelante. Mientras tanto, alguna instancia aprovisionada hace ocho meses, sin motivo para redesplegarse desde entonces, sigue corriendo la versión con la que nació.

Una aplicación normal tiene un entorno de producción, así que «¿funcionó el despliegue?» es un sí o no que respondes una vez. Aquí es un sí o no distinto por cada cliente. Trata una versión como terminada en el momento en que la etiquetas y acabarás publicando un arreglo —un parche de seguridad, un cambio de esquema en el contrato de contenido por sitio— que una fracción significativa de tu flota activa nunca recibe. Una etiqueta es la promesa de que existe una versión. Una subida de restricción y un redespliegue son la promesa de que un cliente la tiene. Sigue ambos como hechos separados, o no te molestes en etiquetar.

La trampa del rancio silencioso tras una cache persistente

El modo de fallo que más horas cuesta diagnosticar: publicas un arreglo real, en el fichero correcto, verificado en local, y en la instancia activa no hace nada. Ni un error. Ni un cambio parcial. Nada. El comportamiento antiguo sigue ocurriendo, y todo tu instinto dice que el despliegue debe de haber fallado, cuando el despliegue funcionó perfectamente.

El sistema editable escribe dos tipos de fichero directamente en disco en la máquina del cliente: el contrato de contenido por sitio y el fichero de mensajes del idioma activo. Ambos son ficheros PHP normales que devuelven un array:

// app/Livewire/Editable.php (baked in by webplo:install-editable)
private function writeConfigFile(array $data, string $filePath): void
{
    $exportedData = var_export($data, true);
    $fileContent = "<?php\n\ndeclare(strict_types=1);\n\nreturn {$exportedData};\n";
    file_put_contents($filePath, $fileContent);

    if (function_exists('opcache_invalidate')) {
        opcache_invalidate($filePath, true);
    }
}

Esas tres últimas líneas son toda la lección. Los ficheros PHP los compila OPcache y se cachean como opcodes, y OPcache no necesariamente se entera de que un fichero cambió en el instante en que file_put_contents() retorna. Revalida según su propio calendario. Así que un cambio que carga configuración —guardar la edición del cliente y redirigir de vuelta a la misma página para mostrarla— puede parecer que no hace nada: la siguiente petición compila el bytecode antiguo de un fichero que, en disco, ya tiene el contenido nuevo. Jurarías que la escritura falló. No falló. La escritura está bien. Es la lectura, milisegundos después, la que sigue mirando al pasado.

Esto es una instancia concreta de una trampa general, y merece decirse claramente porque volverá a encontrarte con otra forma: cualquier cambio en cómo un paquete distribuido carga configuración tiene que asumir que hay una caché de ejecución persistente entre la escritura y la siguiente lectura, e invalidar esa caché explícitamente como parte del arreglo, no como una ocurrencia tardía que esperas que resuelva el redespliegue. Un redespliegue reinicia el proceso y lo limpia todo por accidente. Un guardar-y-recargar dentro de un proceso ya en marcha, no. Prueba sólo el caso del redespliegue y lo publicarás, lo verás pasar, y luego lo verás fallar en silencio delante de un cliente real, porque el entorno que lo rompió no es el que comprobaste.

opcache_invalidate($filePath, true) es todo el arreglo: tres líneas diciéndole a OPcache directamente que ese fichero está rancio justo después de escribirlo. Averiguar que lo necesitabas costó bastante más, porque «no pasó nada» no señala a una caché como una traza señala a un número de línea. Escribe la invalidación y escribe una prueba que demuestre que la siguiente petición tras la escritura ve el valor nuevo, no sólo que el fichero en disco cambió. La escritura nunca fue el riesgo. La lectura sí.