Skip to content

fix(server): guard concurrent collector runs, report stale devices, optional auto-archive - #975

Merged
Starosdev merged 3 commits into
betafrom
fix/965-server-operations
Oct 13, 2026
Merged

Starosdev merged 3 commits into
betafrom
fix/965-server-operations

Conversation

@Starosdev

@Starosdev Starosdev commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner

Summary

WP-E (server operations) for the 2.0.0 release. On-demand collector runs can no longer overlap and now run every bundled collector, and /api/summary reports when each device last reported and whether it is stale, with optional auto-archiving of devices that stop reporting.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • CI/CD or infrastructure change

Related Issues

Related to #965. Addresses #533.

Changes Made

  • POST /api/collectors/run: a request while a run is active returns 409 (breaking footer on 39bd9bc). The handler iterates the shared omnibus.CollectorSpecs, so btrfs, filesystem, and performance collectors also run; binaries missing from PATH are skipped. Route group unchanged; admin scope comes with the API token work.
  • /api/summary (plain and paginated): per device last_seen (omitted when the device never reported) and stale (omitted when last-seen data could not be loaded), computed with the same rule the missed-ping monitor uses (new models.Device.MissedPingTimeout and IsStale, now shared by both). Archived and never-seen devices are never stale. Works whether or not missed-ping notifications are enabled. A 0 or negative global timeout falls back to the 60-minute default, as in the monitor. Muted devices still report stale. Last-seen data is cached for 30 seconds; a query failure is logged and leaves both fields unset rather than failing the summary.
  • web.devices.auto_archive_stale_days (config file, default 0 = off): the monitor tick on the leader archives devices silent for longer than max(days, the device's missed-ping timeout) through the existing archive path, removes them from MQTT, and sends one notification per tick listing them. Never-seen devices are skipped. Auto-archived devices stay archived until unarchived manually. A startup warning is logged when the setting is shorter than the global missed-ping timeout.
  • docs/openapi.yaml (summary fields) and example.scrutiny.yaml (new setting).

Testing

  • I have tested this locally
  • I have added/updated tests that prove my fix/feature works
  • All existing tests pass

go build ./..., go vet ./..., go test ./..., go test -race on web, web/handler, models; golangci-lint run --new-from-rev=origin/beta (v2.14.0, linux/amd64) 0 issues. Tests: concurrent run returns 409, all available collectors invoked, stale rule with per-device override, summary fields, auto-archive.

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my code
  • I have commented my code where necessary (particularly complex areas)
  • I have updated the documentation if needed
  • My changes generate no new warnings

Notes

  • The manual-run lock is in-process and does not serialize with omnibus scheduled runs, which are separate child processes. Same as before this PR.
  • A persistent auto_archived flag (so a returning device could be unarchived automatically) needs a migration; deferred to the migration work.
  • The auto-archive setting is config-file only; a settings-UI version needs a seeded settings row (migration work).
  • A device that stops being registered after a failed smartctl --info (fix(collector): skip unidentified devices, add exclude list and bounded parallel collection #969) goes stale only if it already has history; that path is not covered by a dedicated test.
  • Frontend follow-up: stale badge and last-seen on dashboard and detail, stale filter.

Review: not required (server change on the beta integration branch; an independent read-only review is being run per release coordination)

…llector

POST /api/collectors/run now returns 409 while a run is active and iterates
omnibus.CollectorSpecs, so btrfs, filesystem and performance run too.
The endpoint stays in the existing protected route group; WP-H scopes
should require admin for it.

BREAKING CHANGE: a second POST /api/collectors/run issued while a run is in progress now returns 409 instead of starting an overlapping run.
…rchive

/api/summary now includes last_seen and stale per device, computed with the
same last-seen data and timeout rules (per-device override, else the global
missed ping timeout) as the missed ping monitor. Devices dropped by a failed
smartctl --info scan stop reporting and become stale like any silent device.

web.devices.auto_archive_stale_days (default 0, off) archives devices not seen
for that many days through the existing device archive path.
…st-seen

Move the missed ping timeout default into Device.MissedPingTimeout so a zero
global value no longer marks every device stale. Make stale a nullable field so
a failed last-seen query is distinguishable from not stale, and cache last-seen
data for 30s. Auto-archive now honors the per-device timeout, warns when the
configured days are below the global timeout, and sends a notification; the
docs state that auto-archived devices stay archived until unarchived manually.
Restore the web.reports.path comment placement.
@Starosdev
Starosdev merged commit 2e26bef into beta Oct 13, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Backend/Go related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant