Laravel Octane: cuándo compensa de verdad y cuándo no
Octane elimina el coste de arranque de PHP en cada petición. Eso cambia mucho más que el rendimiento: cambia lo que puedes asumir sobre el estado de tu aplicación.
El modelo tradicional de PHP tiene una propiedad que damos por sentada hasta que desaparece: cada petición empieza de cero. Se arranca el framework, se registran los service providers, se resuelve la configuración, se atiende la petición y se destruye todo. Empezar limpio cada vez es lento, pero es enormemente cómodo: es imposible que una petición contamine a la siguiente.
Octane rompe ese modelo. La aplicación se arranca una vez y se queda en memoria atendiendo peticiones sucesivas. Lo que se ahorra es el arranque completo del framework en cada llamada.
Dónde se nota
No en todas partes por igual. La mejora es proporcional al peso del arranque frente al peso del trabajo real de la petición.
Un endpoint que ejecuta una consulta pesada de veinte segundos no va a mejorar de forma apreciable: el arranque era ruido comparado con el trabajo. En cambio, un endpoint de consulta que responde en pocos milisegundos y se llama constantemente sí cambia de categoría, porque ahí el arranque era una fracción sustancial del tiempo total.
Por eso Octane brilla especialmente en rutas de lectura muy solicitadas: consultas de disponibilidad, catálogos, búsquedas, endpoints internos entre servicios. Es decir, justo donde el volumen es alto y el trabajo por petición es pequeño.
El precio: el estado deja de limpiarse solo
Esta es la parte que rara vez aparece en los artículos de introducción, y es la que de verdad importa.
Con Octane, todo lo que guardes en una propiedad estática, en un singleton del contenedor o en una variable global sobrevive a la petición. Código que llevaba años funcionando puede empezar a comportarse mal, no por un fallo nuevo, sino porque una suposición que siempre fue cierta ha dejado de serlo.
Los patrones que se vuelven peligrosos:
- Singletons que capturan la petición actual. Si un servicio registrado como singleton recibe
la
Requesten su constructor, se queda con la primera para siempre. Todas las peticiones siguientes usarán datos de un usuario que ya se fue. - Propiedades estáticas usadas como caché. Funcionaban como caché por petición. Ahora son caché de proceso, con visibilidad entre usuarios distintos.
- Estado global acumulativo. Cualquier array estático al que se le van añadiendo elementos crece indefinidamente. En el modelo tradicional se vaciaba solo; ahora es una fuga de memoria.
La regla mental es sencilla: lo que dependa de la petición no puede vivir más que la petición. Si algo se resuelve una vez y se reutiliza, tiene que ser genuinamente independiente de quién está llamando.
Cómo lo abordaría
No lo actives en una aplicación grande y te vayas a casa. Actívalo en un entorno idéntico a producción y observa. Los problemas de estado compartido no aparecen en la primera petición; aparecen en la tercera, y a menudo solo bajo concurrencia.
Busca los singletons antes de activarlo. Revisar los service providers y preguntarse, uno por uno, si ese objeto puede sobrevivir entre peticiones es un rato bien invertido. Es mucho más barato que diagnosticarlo con usuarios reales viendo datos de otros.
Vigila la memoria desde el primer día. En el modelo tradicional una fuga de memoria era casi irrelevante, porque el proceso moría enseguida. Con Octane, un crecimiento lento y constante acaba tumbando el worker.
Entonces, ¿compensa?
Si el sistema tiene rutas de consulta muy solicitadas y respuestas pequeñas, compensa mucho, y a veces evita tener que escalar horizontalmente antes de tiempo.
Si el sistema es mayoritariamente trabajo pesado por petición, o si la base de código está llena de estado global que nadie se atreve a tocar, el retorno es bajo y el riesgo alto. En ese caso, la conversación honesta no es sobre Octane: es sobre por qué hay tanto estado global.