> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vexlo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Retention

> Understand queue pressure, delivery failures and the separate lifetimes of stored execution data.

The server keeps recorded calls, captured values and function history under separate limits.
The relay manages queue files on each application host. Configure these limits for the data
window and server outages you need to accommodate.

## Stored execution data

| Data | Default limit | Configuration |
| - | - | - |
| Traces, recorded calls and attempts | 7 days | `-shape-retention-days` |
| Captured arguments, return values, errors and logs | 20 GiB byte budget | `-value-budget-bytes` |
| Observed function relationships | 90 days since the relationship was last observed | No CLI setting |

A trace can outlive its captured values, and function relationships can outlive their example
traces. Trace retention is measured from the server's first receipt time, not the application's
execution start time.

The function index expires inactive relationships, not individual observations in a rolling
window. Counts accumulate while a relationship remains present; an active relationship can
retain counts and a first observation older than 90 days.

## Local queue retention and outages

The SDK never deletes queue files. If the relay is stopped, the SDK continues writing and the
queue grows until storage is exhausted. A running relay manages queue cleanup and pressure
retention independently of the server's storage limits.

| Situation | Queue behavior | Recovery |
| - | - | - |
| Relay stopped | SDK files accumulate; no relay retention runs | Restart the relay against the same queue |
| Server unreachable or retryable response | Batch remains pending for retry | Restore the destination before queue pressure evicts unsent data |
| Server accepts records | Relay accounts for them and advances its delivery cursor | Normal cleanup removes fully drained hours after the grace period |
| Terminal rejection | Relay counts dropped records and advances past them | Correct future delivery; rejected records are not automatically sent again |

The relay's queue budget defaults to 2 GiB. Normal cleanup removes a fully drained hour once
it is past the five-minute finality grace. Pressure cleanup can instead remove the oldest
eligible hour even when it contains unsent records. Those drops are counted as
`daemon_spool_expired`. The retention sweep runs every minute by default.

The current hour and hours still inside the grace window are protected from pressure cleanup.
The queue can therefore remain above its configured budget when no eligible hour remains.
The budget is not a guarantee that any fixed outage duration is safe; recording volume and
available disk space determine how much backlog you can retain.

### Retryable failures and terminal rejection

The relay retries network failures, `429`, and HTTP `500`, `502`, `503` and `504`. Other
response statuses are terminal for the batch; this includes invalid credentials and a token
with the wrong role. Per-record rejections in a successful batch response are terminal for
those records as well.

Terminal records increment `daemon_terminal_reject`, then the cursor advances past them.
Correcting a token or destination later does not cause those records to be retried. Raw queue
files can remain until normal cleanup, but their presence does not mean they are pending.
Do not reset delivery cursors or edit queue files.

Use [Troubleshooting](https://docs.vexlo.ai/deployment/troubleshooting.md) to distinguish a growing backlog from
records already accounted for as drops.

## Value-budget enforcement

When server-side values exceed their budget, retention deletes the oldest whole hour segments
of value files. A pass runs every 10 minutes and performs bounded work. This is not an exact
expiry timer for each value. The write path can also retain call records while declining new
value bytes under budget pressure.

## Estimate capacity

Set the server's data directory and run the capacity check using your expected sustained rate
in traces per second. Replace the path below with the directory used by `vexlo serve`:

```sh theme={"system"}
export VEXLO_DATA_DIR=/path/to/server/data
vexlo check -expected-write-rate 30
```

The check uses a fixed estimate of 28,700 value bytes per trace, not a measurement of your
application. It compares the resulting value lifetime with the configured call-record
retention. The default expected rate, when omitted, is 2 traces per second.

At 30 traces per second, the check succeeds and reports this retention calculation (excerpt):

```text theme={"system"}
retention arithmetic (at 30 traces/s):
  shape bytes/trace:          2300
  value bytes/trace:          28700
  total bytes/trace:          31000
  configured shape retention: 168h0m0s
  effective value retention:  6h55m41.738072009s
  values expire before shapes: a trace keeps its values for 6h55m41.738072009s of the 168h0m0s its shape is searchable; raise -value-budget-bytes or lower the value sample rate to close the gap
```

The check reports the estimated value lifetime even when it is shorter than call-record
retention. That difference does not fail the check. Increase `-value-budget-bytes` to retain
more values, or reduce value sampling to write fewer bytes.

Both `check` and `serve` reject a budget greater than the total capacity of the value-store
volume unless `-allow-overcommit` is set. A budget greater than current free space produces a
warning.

## Interpret unavailable values

Read full values through the values endpoint. Trace detail resolves a `pending` handle to
`stored` when its bytes are readable, but does not recheck every previously stored handle.
A preview alone does not establish that full bytes remain available.

`expired` means that the capture record refers to bytes that are unavailable. They were either
reclaimed or have not arrived. The server does not retain the arrival history needed to distinguish
those causes.

A `pending` capture becomes `stored` when its bytes are readable. If it remains `pending`,
the response does not establish why the bytes are unavailable or whether a later read will
find them. The recording's completeness and root status do not resolve value availability.

## Verify storage and delivery separately

Authenticated `GET /v1/health` reports server storage usage, budget and mode. Relay
`/healthz`, `/metrics` and `relay status` describe the local forwarding process and queue.
A healthy empty queue does not prove every record was accepted: terminal drops can leave
zero backlog. Compare sent and dropped counters, then verify an identified application trace.

See [Configuration](https://docs.vexlo.ai/deployment/configuration.md) for exact settings and
[HTTP traces and values](https://docs.vexlo.ai/reference/http-traces.md) for the read contract.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.