appconfig: fix round 1 — gate SyncUnits loops on syncable||Stamped, not unitDelivered
unitDelivered is (syncable && Backing==unit) || Stamped, so gating on it made unitDelivered && !Stamped force Backing==unit — the exec-backed skip branch (rt.Backing != registry.BackingUnit) became unreachable and its log line stopped printing for exec-backed routes. Gate both SyncUnits loops on syncable(rt) || Stamped(rt) instead; unitDelivered is unchanged for UnitConfigApps and the fingerprint. Extends TestSyncSkipsExecBackedRoutes to assert the exec-backed line is still printed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 files changed,
+14
−8
internal/appconfig/sync.go+2 −2internal/appconfig/sync_test.go+12 −6
diff --git a/internal/appconfig/sync.go b/internal/appconfig/sync.go| index be42a73a0..66e10e488 100644 |
| --- a/internal/appconfig/sync.go |
| +++ b/internal/appconfig/sync.go |
| @@ -117,7 +117,7 @@ func SyncUnits(ctx context.Context, reg *registry.Registry, s release.Store, pri |
| return d |
| } |
| for _, rt := range routes { |
| - if !unitDelivered(rt) { |
| + if !(syncable(rt) || Stamped(rt)) { |
| continue |
| } |
| k := groupKey{release.RouteAccount(rt), rt.App, rt.Environment} |
| @@ -154,7 +154,7 @@ func SyncUnits(ctx context.Context, reg *registry.Registry, s release.Store, pri |
| resolved[k] = resolution{m: m, defaultMissing: !def.found} |
| } |
| for _, rt := range routes { |
| - if !unitDelivered(rt) { |
| + if !(syncable(rt) || Stamped(rt)) { |
| continue |
| } |
| r := resolved[groupKey{release.RouteAccount(rt), rt.App, rt.Environment}] |
diff --git a/internal/appconfig/sync_test.go b/internal/appconfig/sync_test.go| index d4e924fa3..c5b13ca36 100644 |
| --- a/internal/appconfig/sync_test.go |
| +++ b/internal/appconfig/sync_test.go |
| @@ -5,6 +5,7 @@ import ( |
| "context" |
| "os" |
| "path/filepath" |
| + "strings" |
| "testing" |
| "github.com/carlosframework/platform/internal/registry" |
| @@ -339,18 +340,23 @@ func TestSyncSkipsExecBackedRoutes(t *testing.T) { |
| t.Fatalf("Upsert: %v", err) |
| } |
| var restarted []string |
| - if err := Sync(ctx, reg, s, privKey, envDir, func(h string) error { |
| - restarted = append(restarted, h) |
| - return nil |
| - }); err != nil { |
| - t.Fatalf("Sync: %v", err) |
| - } |
| + out := captureStdout(t, func() { |
| + if err := Sync(ctx, reg, s, privKey, envDir, func(h string) error { |
| + restarted = append(restarted, h) |
| + return nil |
| + }); err != nil { |
| + t.Fatalf("Sync: %v", err) |
| + } |
| + }) |
| if _, err := os.Stat(filepath.Join(envDir, "execshape.example.com.env")); !os.IsNotExist(err) { |
| t.Fatalf("expected no env file for an exec-backed route, stat err = %v", err) |
| } |
| if len(restarted) != 0 { |
| t.Fatalf("restarted = %v, want none", restarted) |
| } |
| + if !strings.Contains(out, "execshape.example.com") || !strings.Contains(out, "exec-backed") { |
| + t.Fatalf("expected the exec-backed skip line naming the host, got %q", out) |
| + } |
| } |
| func TestSyncReapsStaleTmpFiles(t *testing.T) { |