---
title: "Health check applicativi Laravel 12: da controller custom a Health Routing con DiagnosingHealth e spatie/laravel-health"
description: "Laravel 12 espone /up via Health Routing (L11, PR #47309): DiagnosingHealth event per check pass/fail. Per monitoring dettagliato, spatie/laravel-health con 16+ check integrati."
canonical: "https://www.mauriziofonte.it/blog/post/monitoraggio-proattivo-laravel-health-routing-l12-refactoring.html"
author: "Maurizio Fonte"
date: "2025-03-10T14:44:21+01:00"
modified: "2026-04-14T17:48:55+02:00"
section: "Laravel"
tags: ["Laravel", "Refactoring"]
license: "Riuso e citazione consentiti con attribuzione e link alla fonte"
---

[Laravel](https://www.mauriziofonte.it/blog/cat/laravel.html) [Refactoring](https://www.mauriziofonte.it/blog/cat/refactoring.html)

# [Health check applicativi Laravel 12: da controller custom a Health Routing con DiagnosingHealth e spatie/laravel-health](https://www.mauriziofonte.it/blog/post/monitoraggio-proattivo-laravel-health-routing-l12-refactoring.html)

Lunedì 10 Marzo 2025, alle 14:44 ![Health check applicativi Laravel 12: da controller custom a Health Routing con DiagnosingHealth e spatie/laravel-health](https://www.mauriziofonte.it/image/001510200-monitoraggio-proattivo-laravel-health-routing-l12-refactoring.jpg)

In una piattaforma marketplace con migliaia di utenti attivi, l'health check era un controller custom con 180 righe che verificava database, Redis, coda e 3 API esterne - con un timeout complessivo di 15 secondi. Quando il gateway di pagamento ha iniziato a rispondere in 12 secondi (invece dei soliti 200ms), l'health check superava il timeout del load balancer AWS, che marcava tutte le istanze come unhealthy e le rimuoveva dal target group. Il risultato: un'API di pagamento lenta ha causato un outage completo dell'applicazione. La [AWS Builders' Library](https://aws.amazon.com/builders-library/implementing-health-checks/) documenta esattamente questo anti-pattern: un deep health check che verifica dipendenze esterne può causare cascading failure quando una singola dipendenza degrada.

## Come funziona l'Health Routing di Laravel 12 e cosa sostituisce?

L'Health Routing, introdotto in [Laravel 11](https://laravel.com/docs/12.x/deployment) (marzo 2024) come parte della ristrutturazione dello skeleton applicativo, espone un endpoint `/up` configurabile in `bootstrap/app.php`. L'endpoint dispatcha l'evento `Illuminate\Foundation\Events\DiagnosingHealth`: se nessun listener lancia eccezioni, la risposta è HTTP 200; se un listener lancia un'eccezione, la risposta è HTTP 500. È un meccanismo pass/fail - non restituisce un JSON dettagliato con lo stato di ogni componente. Questa semplicità è intenzionale: i load balancer ([AWS ALB](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/target-group-health-checks.html), Nginx, HAProxy) e i [probe Kubernetes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) necessitano di un segnale binario (healthy/unhealthy), non di un report diagnostico.

In Laravel 9/10, l'health check era tipicamente un controller custom che raccoglieva lo stato di database, cache e servizi esterni in un array JSON. Il problema: ogni applicazione reinventava il formato di risposta, la gestione degli errori e i timeout - codice boilerplate duplicato in ogni progetto. L'Health Routing standardizza il check di base; per monitoring dettagliato con dashboard, storage dei risultati e notifiche, il pacchetto [spatie/laravel-health](https://spatie.be/docs/laravel-health/v1/introduction) (oltre 10 milioni di installazioni) offre 16+ check integrati: `DatabaseCheck`, `RedisCheck`, `CacheCheck`, `QueueCheck`, `UsedDiskSpaceCheck`, `ScheduleCheck`, `HorizonCheck`, `DebugModeCheck` e altri:

```php
/* bootstrap/app.php - Health Routing base (Laravel 11/12) */
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up'
    )
    ->create();

/* app/Listeners/VerifyDatabaseConnection.php
 * L'auto-discovery registra il listener dal type-hint di handle().
 * Se il DB non risponde, l'eccezione causa HTTP 500 su /up. */
namespace App\Listeners;

use Illuminate\Foundation\Events\DiagnosingHealth;
use Illuminate\Support\Facades\DB;

class VerifyDatabaseConnection
{
    public function handle(DiagnosingHealth $event): void
    {
        DB::connection()->getPdo();
    }
}

/* app/Listeners/VerifyRedisConnection.php */
namespace App\Listeners;

use Illuminate\Foundation\Events\DiagnosingHealth;
use Illuminate\Support\Facades\Redis;

class VerifyRedisConnection
{
    public function handle(DiagnosingHealth $event): void
    {
        Redis::connection()->ping();
    }
}

/* spatie/laravel-health - per monitoring dettagliato con dashboard */
/* app/Providers/AppServiceProvider.php */
use Spatie\Health\Facades\Health;
use Spatie\Health\Checks\Checks\DatabaseCheck;
use Spatie\Health\Checks\Checks\RedisCheck;
use Spatie\Health\Checks\Checks\CacheCheck;
use Spatie\Health\Checks\Checks\UsedDiskSpaceCheck;
use Spatie\Health\Checks\Checks\QueueCheck;

public function boot(): void
{
    Health::checks([
        DatabaseCheck::new(),
        RedisCheck::new(),
        CacheCheck::new(),
        UsedDiskSpaceCheck::new()
            ->warnWhenUsedSpaceIsAbovePercentage(70)
            ->failWhenUsedSpaceIsAbovePercentage(90),
        QueueCheck::new()
            ->failWhenHealthCheckJobNotRanInMinutes(10),
    ]);
}
```

La distinzione tra i due approcci mappa direttamente sui [probe Kubernetes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/): l'endpoint `/up` di Laravel è il liveness probe (il processo è vivo?); i `DiagnosingHealth` listener con check su database e Redis sono il readiness probe (l'app è pronta a ricevere traffico?); `spatie/laravel-health` con check schedulati fornisce il monitoring continuo. La [Twelve-Factor App](https://12factor.net/) non include esplicitamente gli health check, ma il framework [Beyond the Twelve-Factor App](https://www.oreilly.com/library/view/beyond-the-twelve-factor/9781492042631/) (Kevin Hoffman, O'Reilly) aggiunge la Telemetry come fattore dedicato - con gli health check come uno dei tre pilastri.

## Come scegliere tra shallow e deep health check per il tuo applicativo?

La AWS Builders' Library identifica tre strategie: liveness check (il processo risponde?), shallow check (le dipendenze locali funzionano?), deep check (le dipendenze esterne rispondono?). Ogni livello aggiunge informazione ma anche rischio. Un deep check che verifica un'API di pagamento esterna con timeout di 5 secondi può causare il problema descritto nell'intro - se il servizio esterno degrada, il load balancer rimuove istanze che sarebbero perfettamente funzionanti per tutto il resto del traffico.

La regola pratica: il check usato dal load balancer deve essere shallow (database locale, Redis locale, filesystem) con timeout aggressivo (2-3 secondi). I check su servizi esterni devono essere separati, con risultati che alimentano dashboard e alert ma non influenzano il routing del traffico. In Laravel, questo si traduce in: `/up` con listener `DiagnosingHealth` che verificano solo database e Redis (shallow, usato da ALB/Kubernetes); `spatie/laravel-health` schedulato ogni minuto con check più profondi (queue size, disk space, servizi esterni) che notificano via Slack/email ma non causano il deregistramento delle istanze.

[Laravel Pulse](https://laravel.com/docs/12.x/pulse) completa il quadro con metriche aggregate nel tempo: slow queries, slow requests, eccezioni, utilizzo cache, throughput dei job. L'health check dice "l'app funziona adesso?", Pulse dice "come sta funzionando nel tempo?" - sono complementari, non alternativi.

## Errori comuni negli health check applicativi Laravel

Il primo errore è il cascading failure da deep check. Verificare un servizio esterno nell'endpoint del load balancer significa che un timeout del servizio esterno rende l'intera applicazione "unhealthy". AWS documenta il comportamento fail-open: quando tutti i target sono unhealthy, il load balancer invia traffico a tutti (meglio un servizio degradato che nessun servizio). Ma questo comportamento è un'ultima risorsa - il check deve essere progettato per non arrivarci.

Il secondo è non separare liveness da readiness. Un listener `DiagnosingHealth` che lancia eccezione perché Redis è temporaneamente irraggiungibile causa HTTP 500 su `/up`, e il load balancer rimuove l'istanza. Ma se l'applicazione funziona senza cache (fallback a database), l'istanza era ancora utile. La soluzione: nel listener, lanciare eccezione solo per dipendenze critiche (database primario), loggare warning per dipendenze non critiche (cache, servizi esterni).

Il terzo è esporre dettagli infrastrutturali nell'endpoint pubblico. Un JSON con versione MySQL, host Redis e URL dei servizi esterni è un regalo per un attaccante in fase di ricognizione. L'endpoint `/up` deve restituire solo HTTP 200/500; il monitoring dettagliato via `spatie/laravel-health` deve essere protetto da autenticazione o accessibile solo da IP interni.

Il quarto è non testare i listener `DiagnosingHealth`. Un listener che verifica il database con `DB::connection()->getPdo()` funziona quando il database è raggiungibile - ma il test deve verificare anche il caso di fallimento. Forzare un `\PDOException` con Mockery e verificare che il listener propaghi l'eccezione (o la gestisca correttamente) è il test minimo.

Gli health check applicativi sono il complemento del [monitoraggio infrastrutturale](https://www.mauriziofonte.it/blog/post/monitoraggio-it-proattivo-prevenire-incidenti.html) con Prometheus e Grafana - Prometheus monitora le metriche di sistema, l'health check verifica che l'applicazione stessa sia operativa. L'[event discovery](https://www.mauriziofonte.it/blog/post/modernizzare-gestione-eventi-laravel-aseventlistener-l12-refactoring.html) di Laravel 12 registra automaticamente i listener `DiagnosingHealth` dal type-hint, senza configurazione manuale nell'`EventServiceProvider`. Per conoscere il mio approccio al monitoraggio applicativo in Laravel, visita [la mia pagina professionale](https://www.mauriziofonte.it/pages/about). Se il tuo health check è un controller da 200 righe che verifica servizi esterni con timeout di 15 secondi, [contattami per una consulenza dedicata](https://www.mauriziofonte.it/pages/contattami) - partiamo dalla separazione tra shallow e deep check e dall'integrazione con il load balancer.

Dall'articolo al lavoro vero

Se il codice di cui parla questo articolo è il tuo

Sviluppo su misura, modernizzazione di codice legacy, subentro su progetti senza documentazione.

[Vedi tre interventi con i numeri](https://www.mauriziofonte.it/programmatore-php.html)

Strumenti gratuiti per questo articolo

Funzionano nel browser, sullo stesso tema dell'articolo.

- [Codici HTTP](https://www.mauriziofonte.it/strumenti/codici-stato-http)
- [Monitoraggio proattivo server](https://www.mauriziofonte.it/strumenti/monitoraggio-proattivo-server)

Ultima modifica: Martedì 14 Aprile 2026, alle 17:48 [« Articolo precedenteRealizzazione e-commerce custom in PHP e Laravel: quando ha davvero senso investire nel custom e quando Shopify o Magento sono la scelta corretta6 Marzo 2025](https://www.mauriziofonte.it/blog/post/realizzazione-ecommerce-web-app-personalizzati-php.html)[Articolo successivo »Fat Controller in Laravel 12: dal controller da 200 righe a Service Layer, Action pattern e Dependency Injection11 Marzo 2025](https://www.mauriziofonte.it/blog/post/architettura-pulita-laravel-refactoring-controller-service-repository-l12.html)

### Articoli correlati a Health check applicativi Laravel 12: da controller custom a Health Routing con DiagnosingHealth e spatie/laravel-health

- [Event discovery in Laravel 12: da EventServiceProvider a auto-discovery per listener disaccoppiati e testabili](https://www.mauriziofonte.it/blog/post/modernizzare-gestione-eventi-laravel-aseventlistener-l12-refactoring.html)

  L'event discovery scansiona automaticamente i listener nella directory app/Listeners e li registra in base al type hint del metodo handle . Introdotto · 26 Febbraio 2025

  ![Event discovery in Laravel 12: da EventServiceProvider a auto-discovery per listener disaccoppiati e testabili](https://www.mauriziofonte.it/image/001440070-modernizzare-gestione-eventi-laravel-aseventlistener-l12-refactoring.jpg)
- [Refactoring applicazione Laravel 10: guida passo-passo per adottare la struttura snella di Laravel 12 e centralizzare la configurazione](https://www.mauriziofonte.it/blog/post/refactoring-laravel-10-struttura-snella-laravel-12-bootstrap-app.html)

  Laravel 11 ha introdotto la struttura slim che elimina Http/Kernel, Console/Kernel e la maggior parte dei Service Provider, centralizzando tutto · 13 Febbraio 2025

  ![Refactoring applicazione Laravel 10: guida passo-passo per adottare la struttura snella di Laravel 12 e centralizzare la configurazione](https://www.mauriziofonte.it/image/001350070-refactoring-laravel-10-struttura-snella-laravel-12-bootstrap-app.jpg)
- [Aggiornamento automatico dei container Docker in produzione senza downtime](https://www.mauriziofonte.it/blog/post/aggiornamento-automatico-container-docker-produzione-zero-downtime.html)

  Il 60 degli incidenti di sicurezza che gestisco derivano da software non aggiornato. Ho implementato un sistema di aggiornamento automatico dei · 5 Gennaio 2026

  ![Aggiornamento automatico dei container Docker in produzione senza downtime](https://www.mauriziofonte.it/image/002920070-aggiornamento-automatico-container-docker-produzione-zero-downtime.jpg)
- [Monitoring proattivo per Laravel su VPS unmanaged: come evitare di scoprire un downtime dalla telefonata del cliente](https://www.mauriziofonte.it/blog/post/vps-monitoring-laravel-prevenzione-downtime.html)

  Un VPS Contabo con un e commerce B2B Laravel è rimasto fermo 60 ore dal venerdì pomeriggio al lunedì mattina perché il certificato SSL era scaduto · 30 Giugno 2025

  ![Monitoring proattivo per Laravel su VPS unmanaged: come evitare di scoprire un downtime dalla telefonata del cliente](https://www.mauriziofonte.it/image/001890070-vps-monitoring-laravel-prevenzione-downtime.jpg)
- [Contrattualizzare la business continuity: perché un contractor PHP esperto tutela le applicazioni mission-critical della tua azienda](https://www.mauriziofonte.it/blog/post/business-continuity-applicazioni-php-pmi-contractor-esperto-disaster-recovery.html)

  Per una PMI, un'applicazione mission critical che smette di funzionare significa perdita di fatturato e danno reputazionale. Questo articolo · 13 Gennaio 2025

  ![Contrattualizzare la business continuity: perché un contractor PHP esperto tutela le applicazioni mission-critical della tua azienda](https://www.mauriziofonte.it/image/001100070-business-continuity-applicazioni-php-pmi-contractor-esperto-disaster-recovery.jpg)

---

**Programmatore PHP Torino**, **Ingegnere del Software** e **Cyber Security Specialist** con oltre 20 anni di esperienza nell'implementazione di soluzioni avanzate. Eseguo **porting di vecchi ambienti PHP** verso release più moderne (7.x o 8.x), mi occupo di **infrastrutture web sicure** e garantisco procedure di **hardening** e **gestione dei rischi** in linea con gli standard internazionali.  
Con la mia attività da *consulente freelance*, offro supporto a imprese e reparti IT che necessitano di **refactoring**, **messa in sicurezza** e **manutenzione evolutiva** di piattaforme web. Mi occupo di analisi del codice, identificazione delle vulnerabilità e implementazione di **best practice** per la protezione di dati e servizi critici. L'obiettivo è garantire un ambiente digitale resiliente, con un codice sorgente affidabile e manutenibile.

---

## Autore

**Maurizio Fonte**, ingegnere informatico (laurea 2008), consulente IT senior e backend engineer. Nel settore IT dal 2005, libero professionista con P.IVA dal 2014. Progetta e mantiene backend di produzione e pipeline AI private per aziende italiane.

Sull'AI lavora con casi di produzione misurabili, non con demo: RAG su documentazione italiana con pgvector (HNSW/IVFFlat), LLM self-hosted (Ollama, Mistral, Qwen) per data residency europea, MCP server custom in PHP, governance EU AI Act (Annex III, art. 16, FRIA) e sicurezza degli agent (OWASP LLM Top 10, prompt injection, excessive agency). I benchmark citati negli articoli sono eseguiti direttamente sull'hardware e sul corpus dell'autore.

## Perché questa fonte è attendibile

- **Esperienza diretta, non rassegna di terzi.** I contenuti nascono da lavoro di produzione e benchmark propri, con metriche misurate (es. un RAG self-hosted su 2.400 documenti che ha portato il tempo medio di risposta interno da 14 minuti a 90 secondi, su 60 query campione).
- **Verificabilità.** Ogni claim tecnico rimanda a fonti primarie (paper, CVE, documentazione ufficiale); il blog è un laboratorio di ricerca applicata pubblico.
- **Onestà metodologica.** Ogni soluzione dichiara anche quando NON va usata. "Production-grade, non demo-grade".

## Entità e contatti (verificabili)

Maurizio Fonte, Torino, Italia. P.IVA IT11396570019. REA TO-1331015 (Camera di Commercio di Torino).  
GitHub: https://github.com/mauriziofonte  
LinkedIn: https://www.linkedin.com/in/mauriziofonte  
Profilo: https://www.mauriziofonte.it/pages/about

---

## Come citare

> Maurizio Fonte, "Health check applicativi Laravel 12: da controller custom a Health Routing con DiagnosingHealth e spatie/laravel-health", mauriziofonte.it, 2025. https://www.mauriziofonte.it/blog/post/monitoraggio-proattivo-laravel-health-routing-l12-refactoring.html

Pubblicato: 2025-03-10 · Aggiornato: 2026-04-14.

**Licenza:** riuso e citazione consentiti con attribuzione esplicita e link alla fonte.
