systemg

Search docs

/
Install

How It Works

State

Runtime files systemg uses to track services.

Location

~/.local/share/systemg/ (user mode) /var/lib/systemg/ (system mode with --sys)

Structure

Supervisor-wide files live at the root. Everything a project persists — its PID map, service state, and cron history — is nested under its own directory, keyed by project.id:

~/.local/share/systemg/
├── sysg.pid                    # Supervisor PID
├── control.sock                # Unix socket for IPC
├── config_hint                 # Last config path
├── supervisor.xml              # Supervisor-wide operator defaults
├── logs/
│   ├── supervisor.log          # Supervisor events
│   ├── arbitration/            # Project-isolated service output
│   │   └── api.log
│   └── gamecast/
│       └── worker.log
└── projects/
    ├── arbitration/            # one directory per project.id
    │   ├── pid.xml             # Service → PID mapping
    │   ├── state.xml           # Service metadata
    │   └── cron_state.xml      # Cron run history
    ├── gamecast/
    │   ├── pid.xml
    │   ├── state.xml
    │   └── cron_state.xml
    └── __loose__/              # project-less (top-level `services:`) bundle
        ├── pid.xml
        ├── state.xml
        └── cron_state.xml

All XML artifacts are written as nested, two-space-indented documents. Compact XML written by older releases remains readable.

Info

Each project owns its directory. A project's monitor, PID map, and state file only ever touch projects/{project.id}/ — so two projects that both declare a service named worker keep entirely separate records, and one project's status can never leak into another's. Isolation is structural, not a convention we remember to honour.

Services declared at the top level of a manifest — with no project — persist under projects/__loose__/. See Projects for how loose services and named projects coexist in one supervisor.

Key files

pid.xml

Maps a project's services to process IDs:

<PidFile>
  <services>
    <name>web</name>
    <pid>67235</pid>
  </services>
  <services>
    <name>db</name>
    <pid>67236</pid>
  </services>
</PidFile>

config_hint

Stores the last config path for commands that need a config-backed project context. sysg status does not require this hint when a supervisor is running; it asks the supervisor for the aggregate status view.

state.xml

Tracks service status, restart counts, and exit codes — keyed by service configuration hash, scoped to the project directory.

cron_state.xml

Per-project cron run history. Each project's scheduled jobs persist here; a shared scheduler loop routes every run to its own project's file.

Persistence

State survives supervisor restarts. A supervisor crash may leave service processes alive, but they are unsupervised until systemg recovers ownership; they cannot restart or enforce dependencies while no supervisor is running.

Clean shutdown removes sysg.pid, control.sock, and config_hint. Stale files after crash? Run sysg purge.

Warning

Upgrading from v0.54.x or older requires sysg purge first. The per-project projects/{project.id}/ layout replaces the older flat pid.xml / state.xml / cron_state.xml that lived directly under the state directory. There is no automatic migration of the old flat files — stop your services, run sysg purge, then start on the new release.

Growth and reclamation

Two things on disk grow with use, and they are bounded differently.

Logs rotate on their own. Each service's active log is capped at 10 MB, after which it rotates and at most 5 numbered backups are kept — roughly 60 MB per service, ceiling. Override per service with logs.max_bytes and logs.max_files, or globally in supervisor.xml. sysg logs --prune trims rotated backups further by age or total size.

State does not shrink on its own. A project's state directory persists after its services stop — that is what makes a project a durable namespace, and what lets sysg status still tell you what happened. Stopping a project does not reclaim it.

Info

For a workload that creates and destroys projects — one project per job, per tenant, per slot — pair the stop with a scoped purge:

$ sysg stop -p slot-42     # take the project's services down
$ sysg purge -p slot-42    # reclaim its state and its logs

purge -p deletes that project's state directory and its log directory, and nothing else. Without it, a churning workload accumulates one directory per project it has ever run.

See also

Dynamic SpawnLogs