Skip to content

feat(daemons): add per-server Daemons (background processes)#26

Merged
fbarrento merged 1 commit into
mainfrom
feat/9-daemons
May 24, 2026
Merged

feat(daemons): add per-server Daemons (background processes)#26
fbarrento merged 1 commit into
mainfrom
feat/9-daemons

Conversation

@fbarrento
Copy link
Copy Markdown
Contributor

Summary

Server-scoped daemon management — $forge->server($id)->daemons() / ->daemon($d). Independent of Sites/Deployments.

  • Data\Daemon (id, command, user, directory?, processes, status, createdAt)
  • Data\CreateDaemonData, Data\UpdateDaemonData (name + config), Data\ListDaemonsOptions (sort + filter[user|site_id|directory])
  • Enums\DaemonUser (root/forge), Enums\DaemonAction (restart/stop/start/empty-log)
  • Requests: GetDaemons, GetDaemon, CreateDaemon (POST), UpdateDaemon (PUT), DeleteDaemon, SendDaemonAction (POST /actions), GetDaemonLog
  • Resources\DaemonsResource (all/iterate/create), DaemonResource (get/update/delete/restart/stop/start/emptyLog/log(): string)
  • ServerResource::daemons() / daemon($id) wired

Spec-vs-runtime findings (for docs/FINDINGS.md)

  • Daemon update 500s with name-onlyconfig (raw supervisor config) is effectively required despite the spec marking it optional.
  • Provisioning race: fresh daemons sit in installinginstalled (never running); restart 500s until installed. Lifecycle test waits on a live un-mocked connector before acting (skipped on replay).
  • Sparse resource: BackgroundProcessResource attributes are only command/user/directory/processes/status/created_at — no name or updated_at.

Test plan

  • composer test — pint, rector, phpstan, 452 tests / 856 assertions, 100% coverage.
  • Lifecycle creates a real sleep 9999 daemon, exercises list/get/update/restart/log, then deletes — 7 fixtures recorded live, log content redacted.

🤖 Generated with Claude Code

Server-scoped daemon management:
$forge->server($id)->daemons() / ->daemon($d).

- Data\Daemon (id, command, user, directory?, processes, status, createdAt)
- Data\CreateDaemonData, Data\UpdateDaemonData (name + config),
  Data\ListDaemonsOptions (sort + filter[user|site_id|directory])
- Enums\DaemonUser (root/forge), Enums\DaemonAction
  (restart/stop/start/empty-log)
- Requests: GetDaemons, GetDaemon, CreateDaemon (POST), UpdateDaemon
  (PUT), DeleteDaemon, SendDaemonAction (POST /actions), GetDaemonLog
- Resources\DaemonsResource (all/iterate/create), DaemonResource
  (get/update/delete/restart/stop/start/emptyLog/log:string)
- ServerResource->daemons()/daemon($id) wired

Spec-vs-runtime findings (for docs/FINDINGS.md):
- Daemon update 500s with name-only; `config` (raw supervisor config) is
  effectively required despite the spec marking it optional.
- Freshly-created daemons sit in `installing` (then `installed` — never
  `running`); restart 500s until installed. Lifecycle test waits on a
  live un-mocked connector before acting (skipped on replay).
- BackgroundProcessResource attributes are sparse (command/user/
  directory/processes/status/created_at) — no `name` or `updated_at`.

452 tests / 856 assertions / 100% coverage.

Closes #9.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@fbarrento fbarrento self-assigned this May 24, 2026
@fbarrento fbarrento merged commit fdb24b2 into main May 24, 2026
26 checks passed
fbarrento added a commit that referenced this pull request May 24, 2026
…it (#28)

Folds the divergences that had only lived in PR descriptions into
docs/FINDINGS.md: ssh-key create 202-empty, the four Sites findings
(server-less GET, runtime-required domain_mode, fresh-site nulls,
PUT-empty), the deployments script/trigger notes, the two daemon findings
(update needs config, install-state race), and the fixture-redaction
hardening from the security audit (#27).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant