Skip to content

Declarative timers: stack-level schedule block rendered to systemd timers, visible to status/drift #449

Description

@gfargo

Problem

Scheduled host-side jobs around a stack currently live outside strut as hand-installed systemd timers or cron entries. From the project-horizon infra repo:

  • stacks/backup/nightly-plane.sh, nightly-sites.sh — nightly DB/site backups, crontab'd manually
  • stacks/media/systemd/media-port-sync.{service,timer} — 60s Gluetun NAT-PMP → qBittorrent port sync
  • stacks/immich/immich-db-backup-sync.{service,timer} — backup off-array sync

Each one: hand-written unit pair, manual install → daemon-reload → enable --now runbook, no drift detection, invisible to strut status.

Proposal

A declarative timers: (or schedule:) block in stack config (services.conf or a timers.conf):

# stacks/media/timers.conf
[port-sync]
exec = ./port-sync.sh
on_calendar = *:*:0/60        # or interval = 60s
env_file = /etc/default/media-port-sync

[nightly-backup]
exec = strut media backup
on_calendar = daily 03:00

strut renders these to systemd .service/.timer pairs and installs them during deploy (reusing the proposed hook-helper strut::install_timer semantics: idempotent, only-if-changed, recorded for uninstall). strut <stack> timers lists them with last/next run (systemctl list-timers parse); drift check flags hand-edited units.

Why

  • Kills the biggest remaining class of "SSH in and install this timer" runbooks.
  • Backup timers can route through strut backup, so pre_backup/post_backup hooks fire on scheduled runs too — today the out-of-band cron scripts silently bypass the whole hook system.

Composes with: hook helper stdlib (rendering/installing), teardown hooks (removal), host-scoped provisioning (host-level vs stack-level timers).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions