Desarrollo con Laravel

Aplicaciones Laravel, creadas y siempre en marcha.

Desde el primer modelo hasta los workers de colas, los despliegues y la actualización años después: escrito, alojado y mantenido por un solo equipo.

Una versión, tal como se ve en el servidor

Todas las aplicaciones Laravel que gestionamos salen del mismo modo: probadas, construidas, cacheadas y activadas sin un segundo de inactividad.

ci ~/app $ php artisan test   PASS  Tests\Feature\CheckoutTest  ✓ a paid order queues the invoice  ✓ a declined card never marks the order paid   PASS  Tests\Unit\VatTest  ✓ vat is added once, on the total app ~/releases/1400 $ composer install --no-dev --optimize-autoloaderInstalling dependencies from lock fileGenerating optimized autoload files app ~/releases/1400 $ php artisan migrate --force   INFO  Running migrations.  2026_09_27_090000_add_due_date_to_invoices ....... DONE app ~/releases/1400 $ php artisan optimize   INFO  Caching framework bootstrap, configuration, and metadata.  config ...................................... DONE  events ...................................... DONE  routes ...................................... DONE  views ....................................... DONE app ~/releases/1400 $ ln -sfn ~/releases/1400 ~/currentapp ~/releases/1400 $ php artisan horizon:terminate && php artisan octane:reload app ~/releases/1400 $ sudo supervisorctl statushorizon                 RUNNING   pid 48211, uptime 0:00:09octane                  RUNNING   pid 31877, uptime 6 days, 2:14:51 app ~/releases/1400 $ php artisan schedule:list  */5 * * * *  php artisan horizon:snapshot ... Next Due: 3 minutes from now  0   2 * * *  php artisan model:prune ........ Next Due: 9 hours from now  0   9 * * *  php artisan invoices:remind .... Next Due: 16 hours from now
Una sesión de ejemplo sobre una aplicación de ejemplo. Los nombres, las rutas y la salida son ilustrativos.
  1. Primero, las pruebas

    Las pruebas se ejecutan antes de que nada llegue al servidor. Una sola prueba fallida detiene la versión.

  2. Dependencias

    Instaladas solo desde el archivo lock, sin paquetes de desarrollo y con un autoloader optimizado.

  3. Migraciones

    Escritas para que el código en ejecución siga funcionando con el nuevo esquema mientras se cambia de versión.

  4. Cachés

    La configuración, los eventos, las rutas y las vistas quedan en caché. A partir de aquí el archivo de entorno ya no se lee, por eso env() solo debe usarse en los archivos de configuración.

  5. El cambio

    Se mueve un enlace y la nueva versión queda en producción. La anterior se conserva en disco por si hay que volver atrás.

  6. Workers

    Horizon termina los trabajos en curso y se reinicia con el código nuevo; Octane recarga sus workers del mismo modo.

  7. Supervisados

    Supervisor mantiene Horizon y Octane en marcha, y vuelve a levantar cualquiera de los dos si se detiene.

  8. El planificador

    Una sola línea de cron ejecuta todas las tareas programadas. Esto es lo que ejecutará a continuación.

De un clic a un trabajo terminado

El trabajo lento sale de la petición. El cliente obtiene una respuesta al instante, y un worker hace el resto en segundo plano.

  1. 01 · Petición POST /checkout

    El cliente paga

    El controlador valida el pedido, lo guarda y responde al instante. Aquí no ocurre nada lento.

  2. 02 · Trabajo PayOrder::dispatch()

    La parte lenta se convierte en un trabajo

    Se despacha después de que la base de datos confirme la transacción, así un worker nunca recoge un pedido que se ha revertido.

  3. 03 · Cola redis · payments

    Espera en su propia cola

    Los pagos tienen su propia cola, así una exportación larga nunca retiene ninguno.

  4. 04 · Worker horizon · supervisor

    Un worker lo recoge

    Con un tiempo límite, reintentos que esperan cada vez más y un límite de cuántos se ejecutan a la vez.

  5. 05 · Notificación OrderPaid → mail, database

    Todos quedan avisados

    El cliente recibe la factura por correo electrónico y el pedido aparece como pagado en tu panel.

Si sigue fallando failed_jobs

Un trabajo que agota sus reintentos se conserva con su error y recibimos una alerta. Se reintenta en cuanto se corrige la causa; nunca se pierde en silencio.

Toda la aplicación, no solo el servidor

Nuestro equipo aporta veinticinco años de PHP a cada proyecto Laravel, desde el primer modelo hasta la actualización años después.

Crear

La aplicación en sí.

Arquitectura
La lógica de negocio en acciones y servicios, no en los controladores. Form requests para la validación y policies para decidir quién puede hacer qué.
Eloquent
Las relaciones se cargan de antemano donde una página las lista, así una página cuesta unas pocas consultas, no cientos. En desarrollo, la carga diferida lanza un error, de modo que el problema se detecta pronto.
Livewire · Inertia
Livewire cuando el equipo escribe PHP y Blade; Inertia con Vue o React cuando el front end es un proyecto aparte.
APIs con Sanctum
Tokens para aplicaciones móviles y socios, sesiones con cookies para tu propio front end y límites de peticiones por cliente.
Pest · PHPUnit
Pruebas para cada flujo que cobra dinero o envía correo, ejecutadas en cada push antes de construir una versión.

Operar

Lo que la mantiene respondiendo.

Colas y Horizon
Colas separadas para el trabajo urgente y el masivo, cada una con sus propios workers, tiempos límite y reintentos, vigiladas en el panel de Horizon.
El planificador
Una sola línea de cron ejecuta todas las tareas. Las que no deben solaparse, o deben ejecutarse en un único servidor, se marcan así.
Octane
Swoole, RoadRunner o FrankenPHP mantienen la aplicación en memoria entre peticiones. Antes de activarlo, revisamos el código en busca de estado que se filtre de una petición a la siguiente.
Redis
Caché, sesiones, colas y bloqueos, sobre un Redis al que no se puede acceder desde internet.
Supervisor
Los workers de colas, Horizon y Octane se ejecutan como procesos supervisados, que se reinician si se detienen y después de cada versión.

Mantener

Lo que la mantiene al día.

Despliegues sin caídas
Cada versión se construye en su propio directorio y se activa con un enlace. Volver atrás es el mismo paso a la inversa.
Registros y excepciones
Archivos de registro diarios conservados durante un tiempo fijado, y cada excepción se nos notifica junto con la petición que la causó.
Actualizaciones
Laravel publica una versión mayor cada año. Actualizamos una aplicación versión a versión, con las pruebas pasando en cada paso.

Lo que configuramos el primer día

Antes de que llegue el primer cliente, cada servidor Laravel que gestionamos tiene todo esto en marcha.

  • Modo de depuración desactivado en producción, y solo el directorio público expuesto a la webAPP_DEBUG=false
  • Workers de colas bajo Supervisor, reiniciados en cada versiónsupervisord
  • Una sola línea de cron para el planificador* * * * * php artisan schedule:run
  • Redis para caché, sesiones y colasCACHE_STORE=redis
  • Configuración, eventos, rutas y vistas en caché en cada versiónphp artisan optimize
  • OPcache activado y reiniciado en cada versiónopcache.validate_timestamps=0
  • Un pool de PHP-FPM dimensionado según la memoria del servidorpm.max_children
  • Versiones en su propio directorio, a un paso de volver atráscurrent → releases/…
  • Los trabajos fallidos se nos notifican, no se quedan en una tablafailed_jobs
  • Rotación de registros y alertas de excepcionesLOG_CHANNEL=daily
  • Una copia de seguridad nocturna de la base de datos, guardada fuera del servidorbackup · offsite
  • Un certificado TLS que se renueva soloLet's Encrypt

Una versión en disco

/var/www/example-app
├── current → releases/1400
├── releases/
│   ├── 1400
│   └── 0930
└── shared/
    ├── .env
    └── storage/
El servidor web apunta a current. Una versión entra en producción en el momento en que se mueve el enlace, y la anterior se conserva para volver atrás.

Háblanos de tu aplicación

Un desarrollo nuevo, una aplicación que necesita alojamiento o una atascada en una versión antigua. Cada proyecto se presupuesta tras una breve conversación.