From 1737b7c2f779f9c36994e1fda844d98bf01510bb Mon Sep 17 00:00:00 2001 From: NekoPunch Date: Sun, 2 Aug 2026 03:18:23 -0700 Subject: [PATCH] fix(atenet): make xDS snapshot versions restart-unique The in-memory version counter restarted at 1 on every router boot; if Envoy reconnected still holding an identical version string the snapshot cache saw a match and skipped the push, stranding Envoy on pre-restart config. Versions now carry a per-process epoch (unix seconds plus a random suffix) so no incarnation repeats an earlier one's strings, even across clock jumps. Fixes #617. --- cmd/atenet/internal/router/xds.go | 5 +++- cmd/atenet/internal/router/xds_test.go | 33 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/cmd/atenet/internal/router/xds.go b/cmd/atenet/internal/router/xds.go index e422376d9..6a6e0f7a8 100644 --- a/cmd/atenet/internal/router/xds.go +++ b/cmd/atenet/internal/router/xds.go @@ -16,6 +16,7 @@ package router import ( "context" + "crypto/rand" "fmt" "log/slog" "net" @@ -104,6 +105,7 @@ type XdsServer struct { snapshot cachev3.SnapshotCache srv serverv3.Server versionCount int64 + versionEpoch string mu sync.Mutex @@ -145,6 +147,7 @@ func NewXdsServer(xdsPort int) *XdsServer { xdsPort: xdsPort, snapshot: cache, srv: srv, + versionEpoch: strconv.FormatInt(time.Now().Unix(), 10) + "-" + rand.Text()[:8], extprocPort: 50051, // matches default extproc port extprocAddr: "127.0.0.1", ingressPort: 8080, @@ -299,7 +302,7 @@ func (x *XdsServer) UpdateSnapshot() error { defer x.mu.Unlock() x.versionCount++ - ver := strconv.FormatInt(x.versionCount, 10) + ver := x.versionEpoch + "-" + strconv.FormatInt(x.versionCount, 10) // Clusters clusters := []types.Resource{ diff --git a/cmd/atenet/internal/router/xds_test.go b/cmd/atenet/internal/router/xds_test.go index 23f9ffdac..918b4cb08 100644 --- a/cmd/atenet/internal/router/xds_test.go +++ b/cmd/atenet/internal/router/xds_test.go @@ -649,3 +649,36 @@ func TestXdsServer_SetOtlpCollector_EmptyDisablesTracing(t *testing.T) { t.Errorf("snapshot contains cluster %q, want it omitted when tracing is disabled", OtlpClusterName) } } + +func TestSnapshotVersionsUniqueAcrossRestarts(t *testing.T) { + deployAndGetVersion := func(t *testing.T, x *XdsServer) string { + t.Helper() + if err := x.UpdateSnapshot(); err != nil { + t.Fatalf("UpdateSnapshot: %v", err) + } + snap, err := x.snapshot.GetSnapshot(NodeID) + if err != nil { + t.Fatalf("GetSnapshot: %v", err) + } + return snap.GetVersion(resourcev3.ClusterType) + } + + seen := map[string]bool{} + first := NewXdsServer(0) + for range 3 { + v := deployAndGetVersion(t, first) + if seen[v] { + t.Fatalf("version %q minted twice by the same server", v) + } + seen[v] = true + } + + restarted := NewXdsServer(0) + for range 3 { + v := deployAndGetVersion(t, restarted) + if seen[v] { + t.Fatalf("version %q reused after restart; Envoy holding that version would not receive the new config", v) + } + seen[v] = true + } +}