carlos / platform Public

edges: headroom is published only with the HA capability, and the meminfo parser lives in one file

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by claude agent, operated by paul@keymail.dev 5447e3f0b47b2e2a152058aa443a16af79a69770 parent c4ce3a8
5 files changed, +50 −48
  • internal/host/edgesfile.go +2 −2
  • internal/host/headroom.go +38 −0
  • internal/host/headroom_linux.go +0 −22
  • internal/host/headroom_other.go +0 −24
  • internal/host/headroom_test.go +10 −0
diff --git a/internal/host/edgesfile.go b/internal/host/edgesfile.go
index f25501684..0bb51d361 100644
--- a/internal/host/edgesfile.go
+++ b/internal/host/edgesfile.go
@@ -284,7 +284,7 @@ type edgesFile struct {
Draining bool `json:"draining,omitempty"`
// Headroom is what placement chooses by (spec 2). It is refreshed when
// the file is written for another reason and on the loop's own tick; a
- // headroom change alone never forces a write (see edgesFilePass).
+ // headroom change alone never forces a write (see edgesFileWrite).
Headroom *edgeHeadroom `json:"headroom,omitempty"`
Generation string `json:"generation"`
@@ -767,7 +767,7 @@ func edgesFileLoop(reg *registry.Registry) {
if sched.timed {
eip = readPublicIP()
}
- ident.Headroom = readHeadroom(dataDir, awakeCount(reg))
+ ident.Headroom = headroomFor(ident.Capabilities, dataDir, reg)
err = edgesFileWrite(ctx, store, reg, ident, eip, &last, sched.timed)
if err != nil {
// Throttled: a bucket that refuses every write (an IAM Deny, an
diff --git a/internal/host/headroom.go b/internal/host/headroom.go
new file mode 100644
index 000000000..756bbf914
--- /dev/null
+++ b/internal/host/headroom.go
@@ -0,0 +1,38 @@
+package host
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/carlosframework/platform/internal/registry"
+)
+
+// headroomFor is the reading the edges loop publishes: nil unless the box
+// has the region-HA capability. A box that publishes headroom is rewritten
+// on every timed pass, so a one-box region (flag off) must not carry one.
+func headroomFor(caps []string, dataDir string, reg *registry.Registry) *edgeHeadroom {
+ if len(caps) == 0 {
+ return nil
+ }
+ return readHeadroom(dataDir, awakeCount(reg))
+}
+
+// parseMemAvailableMiB returns the MemAvailable line in MiB, or 0.
+func parseMemAvailableMiB(meminfo string) int64 {
+ for _, line := range strings.Split(meminfo, "\n") {
+ rest, ok := strings.CutPrefix(line, "MemAvailable:")
+ if !ok {
+ continue
+ }
+ fields := strings.Fields(rest)
+ if len(fields) == 0 {
+ return 0
+ }
+ kb, err := strconv.ParseInt(fields[0], 10, 64)
+ if err != nil {
+ return 0
+ }
+ return kb / 1024
+ }
+ return 0
+}
diff --git a/internal/host/headroom_linux.go b/internal/host/headroom_linux.go
index 6a23ca9c0..9fbeccd70 100644
--- a/internal/host/headroom_linux.go
+++ b/internal/host/headroom_linux.go
@@ -4,8 +4,6 @@ package host
import (
"os"
- "strconv"
- "strings"
"golang.org/x/sys/unix"
)
@@ -23,23 +21,3 @@ func readHeadroom(dataDir string, awake int) *edgeHeadroom {
}
return h
}
-
-// parseMemAvailableMiB returns the MemAvailable line in MiB, or 0.
-func parseMemAvailableMiB(meminfo string) int64 {
- for _, line := range strings.Split(meminfo, "\n") {
- rest, ok := strings.CutPrefix(line, "MemAvailable:")
- if !ok {
- continue
- }
- fields := strings.Fields(rest)
- if len(fields) == 0 {
- return 0
- }
- kb, err := strconv.ParseInt(fields[0], 10, 64)
- if err != nil {
- return 0
- }
- return kb / 1024
- }
- return 0
-}
diff --git a/internal/host/headroom_other.go b/internal/host/headroom_other.go
index 84d4fa384..543706db6 100644
--- a/internal/host/headroom_other.go
+++ b/internal/host/headroom_other.go
@@ -2,29 +2,5 @@
package host
-import (
- "strconv"
- "strings"
-)
-
// readHeadroom has no readings off Linux: only the awake count.
func readHeadroom(dataDir string, awake int) *edgeHeadroom { return &edgeHeadroom{Awake: awake} }
-
-func parseMemAvailableMiB(meminfo string) int64 {
- for _, line := range strings.Split(meminfo, "\n") {
- rest, ok := strings.CutPrefix(line, "MemAvailable:")
- if !ok {
- continue
- }
- fields := strings.Fields(rest)
- if len(fields) == 0 {
- return 0
- }
- kb, err := strconv.ParseInt(fields[0], 10, 64)
- if err != nil {
- return 0
- }
- return kb / 1024
- }
- return 0
-}
diff --git a/internal/host/headroom_test.go b/internal/host/headroom_test.go
index c5c870160..5292dc0ba 100644
--- a/internal/host/headroom_test.go
+++ b/internal/host/headroom_test.go
@@ -14,3 +14,13 @@ func TestParseMemAvailable(t *testing.T) {
t.Fatalf("unparseable: got %d, want 0", got)
}
}
+
+func TestHeadroomOnlyPublishedWithTheCapability(t *testing.T) {
+ reg := edgesTestRegistry(t)
+ if got := headroomFor(nil, t.TempDir(), reg); got != nil {
+ t.Fatalf("flag off: headroom = %+v, want nil", got)
+ }
+ if got := headroomFor([]string{capRegionHA1}, t.TempDir(), reg); got == nil {
+ t.Fatal("flag on: headroom is nil")
+ }
+}