Repository navigation
Small Bug Fixes and performance flags - #437
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved environment-variable validation and placement-handling issues remain.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (3)
What changed in this PR
Adds WithLive race protection and opt-in controls for core environment variables, startup cleanup, and validator placement.
Changes:
- Serializes concurrent StatefulSet updates.
- Adds
--core-envand--skip-startup-sweep. - Adds validator anti-affinity and placement validation.
| File | Description |
|---|---|
src/FSLibrary/StellarStatefulSets.fs |
Serializes live-state updates. |
src/FSLibrary/StellarOrphanSweep.fs |
Adds startup sweep decision logic. |
src/FSLibrary/StellarMissionContext.fs |
Adds mission fields and environment parsing. |
src/FSLibrary/StellarKubeSpecs.fs |
Adds environment injection and validator affinity. |
src/FSLibrary/StellarFormation.fs |
Provides formation state locking. |
src/FSLibrary/StellarCoreCfg.fs |
Defines validator labels. |
src/FSLibrary/MinBlockTimeTest.fs |
Validates validator placement. |
src/FSLibrary.Tests/Tests.fs |
Tests new controls and placement behavior. |
src/App/Program.fs |
Exposes and wires new options. |
doc/one-validator-per-host.md |
Documents placement behavior. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
9010dda to
0c7c75d
Compare
0c7c75d to
134b2e1
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Four moderate issues remain around rate limiting, reserved environment variables, and malformed --core-env validation.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (5)
Allowing core-env collisions overrides fixed peer environment variables Rate-limit the new namespaced pod list request · New Reject blank entries and invalid environment variable names Empty core-env entries bypass malformed-input validation Placement violation aborts mission instead of failing candidate
134b2e1 to
dd4baeb
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved moderate findings affect environment validation, autoscaler detection, and job-only mission behavior.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (6)
Allowing core-env collisions overrides fixed peer environment variables Stale pod events can misclassify replacement validator runs · New Rate-limit the new namespaced pod list request Reject blank entries and invalid environment variable names Empty core-env entries bypass malformed-input validation Placement violation aborts mission instead of failing candidate
dd4baeb to
99da71b
Compare
99da71b to
04160a6
Compare
drebelsky
left a comment
There was a problem hiding this comment.
The first two commits look fine to me (just some small nits that could be ignored). The third one feels a little more odd to me. From the naming, I would've expected --one-validator-per-host to only apply to validators but it also applies to watchers. Then, there are some places where the checking might get missed (e.g., restarts in max tps). More holistically, though, it seems like this might be the wrong layer to make the change. If we're only scheduling one stellar-core instance per host, the kube spec sizes and Karpenter sizes are very mismatched (perhaps we should instead do something like how the MaxTPS Jenkins job got adjusted to have one properly sized host per pod).
04160a6 to
3cdf282
Compare
|
Thanks for your feedback! I believe it's been addressed |
drebelsky
left a comment
There was a problem hiding this comment.
The first two commits seem fine. I don't fully understand the third commit, but since it is gated behind the flag, intended to unstick perf-testing, and is otherwise mostly a no-op, it seems okay.
Missions stop and start core sets concurrently (e.g. MaxTPS and MinBlockTime restart every node with Async.Parallel). WithLive's read-modify-write of the formation's network config and StatefulSet list was unsynchronized, so two core sets could race and one's live update was lost: its StatefulSet was rebuilt with 0 replicas and the network waited forever for the missing peer. Guard the state update and the StatefulSet replace with a per-formation lock. The readiness wait stays outside the lock so nodes still come up in parallel. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
NAME=VALUE entries, given after one --core-env as `--core-env A=1 B=2`, are added to the stellar-core container environment after the fixed variables; the overlay child process inherits them. Blank or malformed entries, names that are not environment variable names and duplicate names are rejected, so a typo cannot silently drop a setting. So are STELLAR_CORE_PEER_SHORT_NAME, which selects the pod's config, and ASAN_OPTIONS (set by --asan-options): the harness sets both itself. Without the flag the container environment is unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The soft topology spread lets the scheduler pack several stellar-core pods on one worker node when few nodes are available, and co-located nodes interfere through resources their requests do not reserve (cores, caches, memory bandwidth, the NIC and the kernel's network stack), which silently changes what a benchmark measures. With the flag, the run's stellar-core StatefulSet pods, validators and watchers alike, get a label and a required pod anti-affinity against each other on kubernetes.io/hostname, scoped to this run so job pods and the HTTP proxy are unaffected. Each core container also requests its limits, so an autoscaler provisions a node sized to what the pod may use rather than to its much smaller request. For identical nodes across runs, pin the instance type too, e.g. --require-node-labels node.kubernetes.io/instance-type:<type>. The placement is checked in one place, WaitForAllReplicasReady, every time a core set's pods come up: at formation creation and on every restart, in every mission. It logs where the pods landed and fails unless they are scheduled and no two of the run's stellar-core pods share a node. When the cluster cannot provide the nodes, the mission fails with the scheduler's reason instead of waiting forever for replicas that can never become ready. It fails as soon as the cluster autoscaler (Karpenter or cluster-autoscaler) reports it cannot provision a node for a pod, or once a pod has been unschedulable for 3 minutes (10 while an autoscaler is provisioning nodes; that normally takes under a minute). Only namespaced pod and event reads are used: the harness typically cannot list nodes, so an up-front node count is not possible. Off by default; without it, pod specs are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
3cdf282 to
2026549
Compare


Stack: #437 → #438 → #439
First of three stacked PRs with a set of changes I've been using to test our milestone targets via
MinBlockTimeTest. Commits are as follows:c2ba02a Serialize concurrent StatefulSet updates in WithLive. This is a bug fix. The mission restarts all nodes at once, and each restart updates shared state (the network config and the StatefulSet list) without
synchronization. Two restarts could race, so one node's update was lost: its StatefulSet came back with 0 replicas and the network waited forever for it. A lock around the update fixes this. Waiting for readiness
stays outside the lock, so nodes still start in parallel.
f60dff8 Add --core-env. A repeatable NAME=VALUE flag that adds environment variables to the stellar-core container, which the overlay child process inherits. This let's us play with ENV configs required by some rust libraries.
3cdf282 Adds
--one-stellar-core-per-host. During testing, I found that scheduling multiple validators on a single node had significant perf implications. This flag makes it such that we schedule all validators on separate worker nodes. Note that for larger topologies, or when the cluster is being used, this might not be possible, in which case we fail relatively fast during scheduling.