Sviluppo Laravel

Applicazioni Laravel, sviluppate e mantenute in funzione.

Dal primo modello ai worker delle code, dai rilasci all'aggiornamento di anni dopo: scritte, ospitate e seguite da un unico team.

Un rilascio, così come appare sul server

Ogni applicazione Laravel che gestiamo va online allo stesso modo: testata, preparata, messa in cache e attivata senza un secondo di interruzione.

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 sessione di esempio su un'applicazione di esempio. Nomi, percorsi e output sono indicativi.
  1. Prima i test

    I test girano prima che qualsiasi cosa arrivi al server. Un solo test fallito blocca il rilascio.

  2. Dipendenze

    Installate solo dal file di lock, senza pacchetti di sviluppo, con un autoloader ottimizzato.

  3. Migrazioni

    Scritte in modo che il codice in esecuzione continui a funzionare con il nuovo schema durante il passaggio al nuovo rilascio.

  4. Cache

    Configurazione, eventi, rotte e viste vengono messi in cache. Da qui in poi il file d'ambiente non viene più letto, ed è per questo che env() va usato solo nei file di configurazione.

  5. Il cambio

    Un link si sposta e il nuovo rilascio è online. Quello precedente resta su disco per un eventuale rollback.

  6. Worker

    Horizon completa i job in corso e riparte con il nuovo codice; Octane ricarica i suoi worker allo stesso modo.

  7. Supervisionati

    Supervisor mantiene in esecuzione Horizon e Octane, e riavvia l'uno o l'altro se si ferma.

  8. Lo scheduler

    Una sola riga di cron esegue ogni attività pianificata. Ecco la prossima che eseguirà.

Da un clic a un job completato

Il lavoro lento esce dalla richiesta. Il cliente riceve subito una risposta e un worker fa il resto in background.

  1. 01 · Richiesta POST /checkout

    Il cliente paga

    Il controller convalida l'ordine, lo salva e risponde subito. Qui non avviene nulla di lento.

  2. 02 · Job PayOrder::dispatch()

    La parte lenta diventa un job

    Inviato dopo il commit del database, così un worker non prende mai in carico un ordine annullato da un rollback.

  3. 03 · Coda redis · payments

    Aspetta nella sua coda

    I pagamenti hanno una coda tutta loro, così un'esportazione lunga non ne blocca mai uno.

  4. 04 · Worker horizon · supervisor

    Un worker lo prende in carico

    Con un timeout, nuovi tentativi che attendono ogni volta più a lungo e un limite a quanti ne girano contemporaneamente.

  5. 05 · Notifica OrderPaid → mail, database

    Tutti vengono avvisati

    Il cliente riceve la fattura via email e l'ordine risulta pagato nella tua dashboard.

Se continua a fallire failed_jobs

Un job che esaurisce i tentativi viene conservato con il suo errore e noi riceviamo un avviso. Viene rieseguito una volta risolta la causa: mai perso in silenzio.

L'intera applicazione, non solo il server

Il nostro team porta venticinque anni di esperienza in PHP in ogni progetto Laravel, dal primo modello all'aggiornamento di anni dopo.

Sviluppare

L'applicazione in sé.

Architettura
Logica di business in azioni e servizi, non nei controller. Form request per la validazione, policy per stabilire chi può fare cosa.
Eloquent
Relazioni caricate in anticipo dove una pagina le elenca, così una pagina costa poche query e non centinaia. In sviluppo il lazy loading genera un errore, così il problema emerge subito.
Livewire · Inertia
Livewire quando il team scrive PHP e Blade; Inertia con Vue o React quando il front end è un progetto a sé.
API con Sanctum
Token per app mobili e partner, sessioni con cookie per il tuo front end e limiti di richieste per ogni client.
Pest · PHPUnit
Test per ogni percorso che incassa denaro o invia email, eseguiti a ogni push prima che venga preparato un rilascio.

Gestire

Ciò che la mantiene reattiva.

Code e Horizon
Code separate per il lavoro urgente e per quello massivo, ognuna con i propri worker, timeout e tentativi, monitorate nella dashboard di Horizon.
Lo scheduler
Una sola riga di cron esegue ogni attività. Le attività che non devono sovrapporsi, o che devono girare su un solo server, sono contrassegnate come tali.
Octane
Swoole, RoadRunner o FrankenPHP tengono l'applicazione in memoria tra una richiesta e l'altra. Prima di attivarlo, controlliamo che nel codice non ci sia stato che passa da una richiesta alla successiva.
Redis
Cache, sessioni, code e lock, su un Redis non raggiungibile da internet.
Supervisor
Worker delle code, Horizon e Octane girano come processi supervisionati, riavviati se si fermano e dopo ogni rilascio.

Mantenere

Ciò che la mantiene aggiornata.

Rilasci senza interruzioni
Ogni rilascio viene preparato in una propria directory e attivato con un solo link. Tornare indietro è lo stesso passaggio al contrario.
Log ed eccezioni
File di log giornalieri conservati per un periodo stabilito, e ogni eccezione segnalata a noi insieme alla richiesta che l'ha causata.
Aggiornamenti di versione
Laravel pubblica una versione major ogni anno. Portiamo avanti un'applicazione una versione alla volta, con i test superati a ogni passaggio.

Cosa configuriamo fin dal primo giorno

Prima che arrivi il primo cliente, ogni server Laravel che gestiamo ha già tutto questo al suo posto.

  • Modalità debug disattivata in produzione e solo la directory pubblica esposta sul webAPP_DEBUG=false
  • Worker delle code sotto Supervisor, riavviati a ogni rilasciosupervisord
  • Una sola riga di cron per lo scheduler* * * * * php artisan schedule:run
  • Redis per cache, sessioni e codeCACHE_STORE=redis
  • Configurazione, eventi, rotte e viste in cache a ogni rilasciophp artisan optimize
  • OPcache attivo e azzerato a ogni rilascioopcache.validate_timestamps=0
  • Un pool PHP-FPM dimensionato sulla memoria del serverpm.max_children
  • Rilasci in directory separate, a un passo dal rollbackcurrent → releases/…
  • Job falliti segnalati a noi, non lasciati in una tabellafailed_jobs
  • Rotazione dei log e avvisi sulle eccezioniLOG_CHANNEL=daily
  • Un backup notturno del database, copiato fuori dal serverbackup · offsite
  • Un certificato TLS che si rinnova da soloLet's Encrypt

Un rilascio su disco

/var/www/example-app
├── current → releases/1400
├── releases/
│   ├── 1400
│   └── 0930
└── shared/
    ├── .env
    └── storage/
Il web server punta a current. Un rilascio è online nel momento in cui il link si sposta, e quello precedente resta per un eventuale rollback.

Raccontaci la tua applicazione

Un nuovo sviluppo, un'applicazione che cerca casa o una ferma a una vecchia versione. Ogni progetto viene preventivato dopo una breve conversazione.