---
title: "Run history, uptime & latency — Alerts for Laravel | Roundly"
description: "Every run is recorded with its latency — query uptime and p95 latency over any window, and prune old history automatically."
url: https://roundly-consulting.com/open-source/docs/alerts-for-laravel/run-history
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Alerts for Laravel](https://roundly-consulting.com/open-source/docs/alerts-for-laravel.md)

# Run history, uptime & latency

Every executed check records one immutable HealthCheckRun (status + wall-clock latency), queryable off the HealthCheck model:

```php
$check = $team->healthChecks()->first();

$check->runs();                            // HasMany, newest first
$check->latestRun();                       // ?HealthCheckRun
$check->uptimePercentage(now()->subDay()); // % of non-alertable runs in the window
$check->p95LatencyMs(now()->subDay());     // 95th-percentile duration in ms
```

```php
$run = $check->latestRun();

$run->status;       // Status::Ok
$run->duration_ms;  // wall-clock latency of check()
$run->message;      // ?string
$run->meta;         // the result meta as stored
$run->ran_at;       // Carbon
```

- Skipped runs are recorded too, and count as up.
- uptimePercentage() is the share of runs whose status is not alertable, rounded to two decimals. It returns 100.0 with no history.
- p95LatencyMs() is a nearest-rank 95th percentile of duration\_ms. It returns 0 with no history.
- Both are computed in the database — uptime is two counts, the p95 one row read at its nearest-rank offset — so the history is never loaded into memory. Without a window they cover the full history.
- The status report does not call them: it batches its own statistics for every row in a fixed number of queries, over the window given as since:, and reports null rather than 100 and 0 for a row with no run in it (see Status reports & health endpoint).

## Retention

Retention is pruned by alerts:prune-runs, auto-scheduled daily when history is enabled, or from code with Health::prune():

```bash
php artisan alerts:prune-runs --days=30
```

```php
use RoundlyConsulting\Alerts\Facades\Health;

Health::prune();    // older than alerts.history.retention_days; returns the number deleted
Health::prune(7);   // older than 7 days
Health::prune(0);   // throws InvalidRetention — below 1 day would delete the whole history
```

Without --days (or a days argument) it uses history.retention\_days (30 by default). --days must be a whole number of at least 1: 0, -1, abc or 1.5 print an error, exit non-zero and delete nothing, and Health::prune() below 1 day throws InvalidRetention. Set history.enabled to false to stop recording runs and scheduling the prune — the report then shows uptime and p95 as null, while uptimePercentage() and p95LatencyMs() return 100.0 and 0.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/alerts-for-laravel.md)
