Skip to main content

How-to guide

Manage storage and disk space

Signals stores every snapshot and query run locally. This guide covers where that data lives, how retention keeps it bounded, how to size the volume, and how to recover when the disk fills up.

Where the data lives

Signals keeps all of its history in a single SQLite database at database.path (default /data/signals.db). Write-ahead logging is on by default (database.wal = true), so alongside the main file you will see a -wal and a -shm sidecar. Every collection cycle appends snapshot rows and query runs to this store, so it grows with the number of targets, the poll cadence, and how long you retain data.

WAL requires a real local filesystem with working fcntl-style file locking. SQLite expects exactly one writer, and the daemon is that writer. Putting database.path on a network filesystem (NFS, SMB) is not supported: WAL does not work reliably there, and you will see database is locked errors. Keep the database on local disk and let the single daemon own it.

How growth is bounded

Retention is what keeps the store from growing forever. Snapshots and query runs older than the retention cutoff are pruned on the daemon's cleanup cycle. You configure it in one of two mutually exclusive ways.

Flat retention

The simplest form is a single cutoff applied to every retention class. The default is 30 days:

signals:
  # Flat retention — one cutoff for everything (default 30).
  retention_days: 30

Structured retention

For finer control you can set per-class cutoffs instead. The structured block and the flat retention_daysare mutually exclusive — set one or the other, never both, or the daemon rejects the config at startup:

signals:
  # Structured retention — per-class cutoffs.
  # Mutually exclusive with retention_days above.
  retention:
    short_days: 14
    medium_days: 30
    long_days: 90
Setting retention_days to 0 or a negative value disables cleanup entirely. The daemon warns: "cleanup is disabled — snapshots and query runs will be retained until the daemon disk fills up". Disabled retention is a deliberate choice for setups that prune externally; if you are not pruning externally, leave retention set or the disk will eventually fill.

Sizing the /data volume

Size the volume that backs database.pathfor the steady state your retention window implies: roughly the per-cycle write volume multiplied by the number of cycles inside the longest retention class, across all targets, plus headroom for the WAL sidecar and for export staging. Give it slack — SQLite reclaims freed space lazily, so the file does not shrink the instant rows are pruned. A volume that is comfortably larger than the projected steady state avoids the full-disk failure mode below.

Symptoms and recovery for a full disk

When the volume backing the database fills up, writes start failing. The signature is a SQLite error such as database or disk is full on collection or export, and the daemon can no longer persist new snapshots. To recover, bring the store back under the volume size:

  • Lower the retention cutoff. Reduce retention_days (or the structured retention.* values) so the next cleanup cycle prunes more history.
  • Grow the volume. If the steady-state size is legitimately larger than provisioned, expand the disk backing database.path.
  • Export and offload, then let pruning catch up. Export the snapshots you need for analysis, move the archive off the host, and let the lowered retention prune the local store back down.

If you had disabled cleanup with retention_days <= 0, re-enabling a positive cutoff is the fix — that is the configuration that lets the disk fill in the first place.

The export-memory caveat

Export assembles the ZIP archive in memory before writing it out, so a single export of a large window can spike memory usage. Export more frequently over narrower time windows to keep the volume per snapshot smaller, rather than exporting one huge range in a single pass.

See also

For the full set of retention and database options, see the Configuration reference. For the offload step in the recovery flow, see Export snapshots.