Skip to content

Commit 80b2389

Browse files
committed
fix(sync): keep degraded polling rooted in provider ownership (#1208)
1 parent b727827 commit 80b2389

12 files changed

Lines changed: 495 additions & 376 deletions

cmd/agentsview/archive_write_backend.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ func newArchivePushUnwatchedPoller(
104104
ticker := time.NewTicker(unwatchedPollInterval)
105105
return newUnwatchedPollCoordinatorWithTicks(
106106
ctx, engine, ticker.C, ticker.Stop, func(work func()) { work() }, nil,
107+
newProviderDegradedPollingResolver(),
107108
)
108109
}
109110

@@ -924,11 +925,10 @@ func (b *localArchiveWriteBackend) PGPushWatch(
924925
},
925926
OnPollingRequired: func(obligation syncpkg.PollingObligation) error {
926927
return poller.AddObligation(pollingObligation{
927-
Key: obligation.Key,
928-
Agent: obligation.Agent,
929-
Roots: obligation.Roots,
930-
Probe: obligation.Probe,
931-
DegradedProbe: obligation.DegradedProbe,
928+
Key: obligation.Key,
929+
Agent: obligation.Agent,
930+
Roots: obligation.Roots,
931+
Probe: obligation.Probe,
932932
})
933933
},
934934
OnPollingReleased: poller.RemoveObligation,

cmd/agentsview/archive_write_backend_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,6 @@ func TestLocalPGPushWatchPropagatesDegradedProbeToArchivePoller(t *testing.T) {
829829
},
830830
database: database,
831831
}
832-
probe := &staticDegradedPollProbe{}
833832
poller := &recordingUnwatchedRootPoller{
834833
added: make(chan pollingObligation, 1),
835834
}
@@ -843,10 +842,10 @@ func TestLocalPGPushWatchPropagatesDegradedProbeToArchivePoller(t *testing.T) {
843842
options syncpkg.WatcherOptions,
844843
) (func(), func(), []string) {
845844
require.NoError(t, options.OnPollingRequired(syncpkg.PollingObligation{
846-
Key: "watch-root|scope",
847-
Roots: []string{filepath.Join(dataDir, "scope")},
848-
Probe: filepath.Join(dataDir, "watch-root"),
849-
DegradedProbe: probe,
845+
Key: "watch-root|scope",
846+
Agent: parser.AgentOpenCode,
847+
Roots: []string{filepath.Join(dataDir, "scope")},
848+
Probe: filepath.Join(dataDir, "watch-root"),
850849
}))
851850
return func() {}, func() {}, nil
852851
},
@@ -881,9 +880,9 @@ func TestLocalPGPushWatchPropagatesDegradedProbeToArchivePoller(t *testing.T) {
881880
select {
882881
case obligation := <-poller.added:
883882
assert.Equal(t, "watch-root|scope", obligation.Key)
883+
assert.Equal(t, parser.AgentOpenCode, obligation.Agent)
884884
assert.Equal(t, []string{filepath.Join(dataDir, "scope")}, obligation.Roots)
885885
assert.Equal(t, filepath.Join(dataDir, "watch-root"), obligation.Probe)
886-
assert.Same(t, probe, obligation.DegradedProbe)
887886
default:
888887
t.Fatal("expected polling obligation to reach archive poller")
889888
}
@@ -953,6 +952,7 @@ func TestLocalPGPushWatchGivesDeferredScopesAPollingOwner(t *testing.T) {
953952
func(roots []string) {
954953
owned <- append([]string(nil), roots...)
955954
},
955+
nil,
956956
)
957957
},
958958
}

cmd/agentsview/main.go

Lines changed: 47 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -330,11 +330,10 @@ func runServe(cfg config.Config, opts serveOptions) {
330330
},
331331
OnPollingRequired: func(obligation sync.PollingObligation) error {
332332
return unwatchedPoller.AddObligation(pollingObligation{
333-
Key: obligation.Key,
334-
Agent: obligation.Agent,
335-
Roots: obligation.Roots,
336-
Probe: obligation.Probe,
337-
DegradedProbe: obligation.DegradedProbe,
333+
Key: obligation.Key,
334+
Agent: obligation.Agent,
335+
Roots: obligation.Roots,
336+
Probe: obligation.Probe,
338337
})
339338
},
340339
OnPollingReleased: unwatchedPoller.RemoveObligation,
@@ -1908,7 +1907,9 @@ func watchPollingObligations(
19081907
result = results[i]
19091908
}
19101909
if !result.MissingRootLifecycleOwned {
1911-
add(root.pollingObligations(root.path, root.path, root.pendingPollingDirs)...)
1910+
add(root.pollingObligations(
1911+
root.path, root.path, root.pendingPollingDirs, false,
1912+
)...)
19121913
}
19131914
for _, dir := range root.persistentPollingDirs {
19141915
cleanDir := filepath.Clean(dir)
@@ -1923,12 +1924,16 @@ func watchPollingObligations(
19231924
// after the obligations are installed leaves its configured dir
19241925
// pollable and the fallback poll reconciles it as an
19251926
// authoritative empty discovery.
1926-
add(root.pollingObligations(root.path, root.path, root.syncDirs())...)
1927+
add(root.pollingObligations(
1928+
root.path, root.path, root.syncDirs(), true,
1929+
)...)
19271930
continue
19281931
}
19291932
if result.Unwatched > 0 || result.BudgetExhausted ||
19301933
result.ResourceExhausted || result.Err != nil {
1931-
add(root.pollingObligations(root.path, root.path, root.syncDirs())...)
1934+
add(root.pollingObligations(
1935+
root.path, root.path, root.syncDirs(), true,
1936+
)...)
19321937
}
19331938
}
19341939
for _, dir := range unwatchedDirs {
@@ -1949,6 +1954,7 @@ func (r watchRoot) pollingObligations(
19491954
rootKey string,
19501955
probePath string,
19511956
dirs []string,
1957+
providerScoped bool,
19521958
) []sync.PollingObligation {
19531959
dirs = deduplicateStrings(dirs)
19541960
if len(dirs) == 0 {
@@ -1959,41 +1965,36 @@ func (r watchRoot) pollingObligations(
19591965
dirFilter[filepath.Clean(dir)] = struct{}{}
19601966
}
19611967
byKey := make(map[string][]string)
1962-
degraded := make(map[string]parser.DegradedPollingStateProbe)
1968+
obligationAgent := make(map[string]parser.AgentType)
19631969
for _, dir := range dirs {
19641970
cleanDir := filepath.Clean(dir)
19651971
key := rootKey
1966-
var (
1967-
probe parser.DegradedPollingStateProbe
1968-
probeAgent parser.AgentType
1969-
probeOK = true
1970-
seen bool
1971-
)
1972+
var agent parser.AgentType
1973+
sameAgent := true
19721974
for _, scope := range r.scopes {
19731975
if filepath.Clean(scope.syncDir) != cleanDir {
19741976
continue
19751977
}
19761978
if _, ok := dirFilter[filepath.Clean(scope.syncDir)]; !ok {
19771979
continue
19781980
}
1979-
seen = true
1980-
if scope.degradedProbe == nil {
1981-
probeOK = false
1982-
break
1983-
}
1984-
if probe == nil {
1985-
probe = scope.degradedProbe
1986-
probeAgent = scope.agent
1987-
continue
1988-
}
1989-
if scope.agent != probeAgent {
1990-
probeOK = false
1991-
break
1981+
if agent == "" {
1982+
agent = scope.agent
1983+
} else if scope.agent != agent {
1984+
sameAgent = false
19921985
}
19931986
}
1994-
if seen && probeOK && probe != nil {
1987+
if providerScoped && sameAgent && agent != "" {
19951988
key = rootKey + "|" + cleanDir
1996-
degraded[key] = probe
1989+
}
1990+
currentAgent := parser.AgentType("")
1991+
if sameAgent {
1992+
currentAgent = agent
1993+
}
1994+
if prior, ok := obligationAgent[key]; !ok {
1995+
obligationAgent[key] = currentAgent
1996+
} else if prior == "" || currentAgent == "" || prior != currentAgent {
1997+
obligationAgent[key] = ""
19971998
}
19981999
byKey[key] = appendUniqueString(byKey[key], cleanDir)
19992000
}
@@ -2007,10 +2008,10 @@ func (r watchRoot) pollingObligations(
20072008
roots := byKey[key]
20082009
slices.Sort(roots)
20092010
obligations = append(obligations, sync.PollingObligation{
2010-
Key: key,
2011-
Roots: roots,
2012-
Probe: filepath.Clean(probePath),
2013-
DegradedProbe: degraded[key],
2011+
Key: key,
2012+
Agent: obligationAgent[key],
2013+
Roots: roots,
2014+
Probe: filepath.Clean(probePath),
20142015
})
20152016
}
20162017
return obligations
@@ -2360,24 +2361,8 @@ func deduplicateStrings(values []string) []string {
23602361
}
23612362

23622363
type watchScope struct {
2363-
agent parser.AgentType
2364-
syncDir string
2365-
degradedProbe parser.DegradedPollingStateProbe
2366-
}
2367-
2368-
type lateBoundDegradedPollProbe struct {
2369-
provider parser.Provider
2370-
root string
2371-
}
2372-
2373-
func (p lateBoundDegradedPollProbe) DegradedPollingState(
2374-
ctx context.Context,
2375-
) (string, error) {
2376-
probe, err := parser.ResolveDegradedPollingProbe(ctx, p.provider, p.root)
2377-
if err != nil {
2378-
return "", err
2379-
}
2380-
return probe.DegradedPollingState(ctx)
2364+
agent parser.AgentType
2365+
syncDir string
23812366
}
23822367

23832368
type watchRoot struct {
@@ -2393,9 +2378,8 @@ func (r watchRoot) registeredRoot() sync.WatchRoot {
23932378
scopes := make([]sync.WatchScope, 0, len(r.scopes))
23942379
for _, scope := range r.scopes {
23952380
scopes = append(scopes, sync.WatchScope{
2396-
Agent: string(scope.agent),
2397-
SyncDir: scope.syncDir,
2398-
DegradedProbe: scope.degradedProbe,
2381+
Agent: string(scope.agent),
2382+
SyncDir: scope.syncDir,
23992383
})
24002384
}
24012385
return sync.WatchRoot{
@@ -2432,13 +2416,11 @@ func collectWatchRoots(cfg config.Config) (
24322416
path string,
24332417
recursive,
24342418
exists bool,
2435-
degradedProbe parser.DegradedPollingStateProbe,
24362419
) {
24372420
path = filepath.Clean(path)
24382421
scope := watchScope{
2439-
agent: agent,
2440-
syncDir: filepath.Clean(dir),
2441-
degradedProbe: degradedProbe,
2422+
agent: agent,
2423+
syncDir: filepath.Clean(dir),
24422424
}
24432425
if idx, ok := rootIndexes[path]; ok {
24442426
roots[idx].recursive = roots[idx].recursive || recursive
@@ -2465,9 +2447,8 @@ func collectWatchRoots(cfg config.Config) (
24652447
root string,
24662448
recursive,
24672449
exists bool,
2468-
degradedProbe parser.DegradedPollingStateProbe,
24692450
) {
2470-
addRoot(def.Type, dir, root, recursive, exists, degradedProbe)
2451+
addRoot(def.Type, dir, root, recursive, exists)
24712452
}
24722453
_, hasProvider := parser.ProviderFactoryByType(def.Type)
24732454
if providerWatched, polling := collectProviderWatchRoots(def, d, addAgentRoot); providerWatched {
@@ -2537,7 +2518,6 @@ func collectProviderWatchRoots(
25372518
root string,
25382519
recursive,
25392520
exists bool,
2540-
degradedProbe parser.DegradedPollingStateProbe,
25412521
),
25422522
) (bool, providerPollingReasons) {
25432523
factory, ok := parser.ProviderFactoryByType(def.Type)
@@ -2568,30 +2548,9 @@ func collectProviderWatchRoots(
25682548
polling.symlinkRoots = append(polling.symlinkRoots, root)
25692549
continue
25702550
}
2571-
degradedProbe, probeErr := parser.ResolveDegradedPollingProbe(
2572-
context.Background(), provider, root,
2573-
)
2574-
if probeErr != nil {
2575-
if errors.Is(probeErr, parser.ErrUnsupportedProviderFeature) &&
2576-
def.Type == parser.AgentOpenCode {
2577-
degradedProbe = lateBoundDegradedPollProbe{
2578-
provider: provider,
2579-
root: root,
2580-
}
2581-
} else if !errors.Is(probeErr, parser.ErrUnsupportedProviderFeature) {
2582-
log.Printf("%s provider degraded poll probe for %s: %v",
2583-
def.Type, root, probeErr)
2584-
degradedProbe = nil
2585-
}
2586-
} else if def.Type == parser.AgentOpenCode {
2587-
degradedProbe = lateBoundDegradedPollProbe{
2588-
provider: provider,
2589-
root: root,
2590-
}
2591-
}
25922551
_, err := os.Stat(root)
25932552
exists := err == nil
2594-
addRoot(dir, root, providerRoot.Recursive, exists, degradedProbe)
2553+
addRoot(dir, root, providerRoot.Recursive, exists)
25952554
if exists {
25962555
continue
25972556
}
@@ -2661,14 +2620,13 @@ func collectLegacyWatchRoots(
26612620
root string,
26622621
recursive,
26632622
exists bool,
2664-
degradedProbe parser.DegradedPollingStateProbe,
26652623
),
26662624
) []string {
26672625
var unwatchedDirs []string
26682626
if def.ShallowWatchRootsFunc != nil {
26692627
for _, watchDir := range def.ShallowWatchRootsFunc(dir) {
26702628
if _, err := os.Stat(watchDir); err == nil {
2671-
addRoot(dir, watchDir, false, true, nil)
2629+
addRoot(dir, watchDir, false, true)
26722630
}
26732631
}
26742632
}
@@ -2679,7 +2637,7 @@ func collectLegacyWatchRoots(
26792637
}
26802638
for _, watchDir := range watchDirs {
26812639
if _, err := os.Stat(watchDir); err == nil {
2682-
addRoot(dir, watchDir, !def.ShallowWatch, true, nil)
2640+
addRoot(dir, watchDir, !def.ShallowWatch, true)
26832641
continue
26842642
}
26852643
unwatchedDirs = append(unwatchedDirs, dir)
@@ -2688,14 +2646,14 @@ func collectLegacyWatchRoots(
26882646
}
26892647
if len(def.WatchSubdirs) == 0 {
26902648
if _, err := os.Stat(dir); err == nil {
2691-
addRoot(dir, dir, !def.ShallowWatch, true, nil)
2649+
addRoot(dir, dir, !def.ShallowWatch, true)
26922650
}
26932651
return unwatchedDirs
26942652
}
26952653
for _, sub := range def.WatchSubdirs {
26962654
watchDir := filepath.Join(dir, sub)
26972655
if _, err := os.Stat(watchDir); err == nil {
2698-
addRoot(dir, watchDir, !def.ShallowWatch, true, nil)
2656+
addRoot(dir, watchDir, !def.ShallowWatch, true)
26992657
}
27002658
}
27012659
return unwatchedDirs

0 commit comments

Comments
 (0)