92 lines
7.4 KiB
Markdown
92 lines
7.4 KiB
Markdown
## Context
|
|
|
|
Platform currently persists `RunEndpoint` rows and stores `ServerInstance.RunEndpointID` as if a server is bound to a durable machine endpoint. The same identifier is then reused for control registration, heartbeat status, job scheduling, UI availability, and component revocation. That model conflicts with the intended architecture: Platform is a registry/dispatcher, while Run is a server-scoped RPC worker that proves possession of a component token, registers a live session, heartbeats, and claims work only while that session lease is current.
|
|
|
|
The recent platform-side builder work already removed distribution builds from machine-side Run authority. This change continues that direction by removing durable run endpoint rows from first-party server runtime routing. Redis becomes the required runtime registry for local development, tests, and production so that all environments exercise the same lease and expiry behavior.
|
|
|
|
## Goals / Non-Goals
|
|
|
|
**Goals:**
|
|
|
|
- Replace durable run endpoint routing with Redis-backed runtime session leases.
|
|
- Route runtime jobs by logical target (`serverInstanceId`, `componentKind`, optional `componentKey`) instead of endpoint rows.
|
|
- Keep server creation, deployment definitions, component auth keys, jobs, logs, artifacts, and audits durable in the database.
|
|
- Make runtime online state, capabilities, capacity, session token hashes, and heartbeat freshness ephemeral and TTL-backed.
|
|
- Require Redis in development and tests; avoid memory-only behavior hiding lease/routing bugs.
|
|
- Preserve platform-owned distribution builds and prevent generated Runs from receiving build authority.
|
|
|
|
**Non-Goals:**
|
|
|
|
- Do not introduce cloud hosting, SSH provisioning, billing, or external marketplace workflows.
|
|
- Do not store raw credentials, host paths, sockets, or plaintext component keys in Redis.
|
|
- Do not move durable job history, audit events, artifacts, or server definitions out of the database.
|
|
- Do not re-add a `run/` source tree to this repository.
|
|
|
|
## Decisions
|
|
|
|
### 1. Redis is the only runtime registry for dev, test, and production
|
|
|
|
Platform SHALL require Redis for runtime registry behavior in every normal environment. Tests may start an isolated Redis instance or use an explicit test Redis database/prefix, but they SHALL NOT swap in a memory registry for ordinary execution.
|
|
|
|
This keeps expiration, reconnect, session loss, and multi-process behavior visible during development. An in-memory registry would be simpler, but it would let tests pass with semantics that fail once Platform runs more than one process or restarts.
|
|
|
|
### 2. Registry data is ephemeral and TTL-owned
|
|
|
|
Redis stores only live-session data:
|
|
|
|
- `runtime:v1:session:{serverInstanceId}:{componentKind}:{componentKey}`
|
|
- `runtime:v1:token:{tokenHash}`
|
|
- optional short-lived indexes for online summaries and capability snapshots
|
|
|
|
Every key has a TTL derived from the heartbeat interval plus a small grace window. Platform startup does not scan or clean Redis. Stale sessions expire naturally, and a Redis flush/restart is treated like all Runs temporarily went offline until they register again.
|
|
|
|
### 3. Component token identity replaces endpoint ownership
|
|
|
|
A generated Run hello includes `serverInstanceId`, `componentKind=run`, component key/generation, registration proof, version, target OS/arch, capabilities, and capacity. Platform authenticates the component key from durable database state, then writes a Redis session lease. The accepted session token is scoped to that server/component and is used for heartbeat, claim, ack, progress, result, logs, and artifact operations.
|
|
|
|
The system does not need a pre-existing endpoint row or a server-to-endpoint foreign key. If two Runs present the same component identity, the later valid registration supersedes the previous session by rotating the token lease.
|
|
|
|
### 4. Jobs target logical components, not endpoints
|
|
|
|
Durable jobs use a logical target:
|
|
|
|
- `serverInstanceId`
|
|
- `targetComponentKind` such as `run`, `client-manager`, or `platform-builder`
|
|
- `targetComponentKey` for keyed components, empty for the server Run
|
|
|
|
Run job claim authenticates the session token, derives the server/component target from Redis, and returns only eligible jobs for that target. Leases remain durable on the job record so retries and audit history survive Platform restarts.
|
|
|
|
### 5. UI shows runtime connection health, not endpoint selection
|
|
|
|
Platform Web replaces endpoint selection/status surfaces with server runtime connection health. The user sees whether the generated Run is registered, heartbeat freshness, version, target OS/arch, capabilities, current capacity, and safe unavailable reasons. The UI does not ask the owner to choose a run endpoint when creating, editing, or deploying a server.
|
|
|
|
### 6. Compatibility is staged but not permanent
|
|
|
|
Existing code paths that accept `runEndpointId` become compatibility shims during migration. They should either translate to logical targets where safe or return a clear deprecation validation error in first-party workflows. New code must not create `RunEndpoint` rows for machine-side generated Runs.
|
|
|
|
## Risks / Trade-offs
|
|
|
|
- [Redis unavailable blocks runtime routing] -> Treat Redis as required platform infrastructure; startup/health checks must report runtime registry unavailable and runtime operations must fail safely without dispatching jobs.
|
|
- [Redis restart marks healthy Runs offline until reconnect] -> Runs already heartbeat frequently; clients retry registration when heartbeat fails or receives an unknown-session response.
|
|
- [Large migration surface] -> Move in phases: registry interface first, job target fields second, UI/API cleanup third, repository deletion last.
|
|
- [Old endpoint-based packages reconnect] -> Compatibility can accept legacy registration only behind explicit migration rules; generated packages should be rebuilt with server/component identity.
|
|
- [Tests become slower with Redis] -> Use a test Redis prefix/database and cleanup by prefix in test setup, while still relying on TTL behavior for session expiry scenarios.
|
|
|
|
## Migration Plan
|
|
|
|
1. Add Redis configuration, health checks, and test harness support; fail fast when Redis is unavailable.
|
|
2. Introduce `RuntimeSessionRegistry` backed by Redis and move Run hello/heartbeat/token validation onto it.
|
|
3. Add durable job logical target fields while temporarily writing both logical target and legacy `runEndpointId`.
|
|
4. Change job claim, ack, progress, result, log, artifact, config, file, and lifecycle dispatch to authorize through registry-derived server/component targets.
|
|
5. Remove first-party server creation/edit/deployment references to run endpoint selection and project runtime connection health from Redis.
|
|
6. Migrate or deprecate legacy endpoint-based records; stop creating `RunEndpoint` rows for generated Runs.
|
|
7. Remove obsolete repository methods, DTO fields, tests, and documentation once compatibility paths are no longer used.
|
|
|
|
Rollback is limited to keeping the compatibility shim and disabling new runtime dispatch. Durable server definitions and jobs remain in the database; Redis contains only disposable session leases.
|
|
|
|
## Open Questions
|
|
|
|
- Should Redis be required at Platform process startup, or can only runtime routes fail health checks while non-runtime admin pages stay available?
|
|
- Which Redis deployment profile should local scripts use by default: Docker Compose service, existing local Redis, or a repo-managed test container?
|
|
- How long should the legacy `runEndpointId` compatibility window remain before API fields are removed?
|