mirror of
https://github.com/lukaszraczylo/ghtracker.git
synced 2026-10-12 00:45:38 +00:00
fix(collector): publish each repository as its scan finishes
A rescan held every result until the last repository finished. The dashboard therefore showed new and resolved alerts only at the end. Each repository now enters the view when its fetch completes. The last scan time, loaded flag and refresh hooks still update at the end.
This commit is contained in:
@@ -155,25 +155,25 @@ func (c *Collector) Refresh(ctx context.Context) {
|
||||
c.limited.Store(false)
|
||||
c.scanDone.Store(0)
|
||||
c.scanTotal.Store(int64(len(c.names)))
|
||||
results := make([]model.Repo, len(c.names))
|
||||
sem := make(chan struct{}, c.concurrency)
|
||||
var wg sync.WaitGroup
|
||||
for i, name := range c.names {
|
||||
for _, name := range c.names {
|
||||
wg.Add(1)
|
||||
sem <- struct{}{}
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
defer func() { <-sem }()
|
||||
results[i] = c.refreshOne(ctx, name, start, true)
|
||||
r := c.refreshOne(ctx, name, start, true)
|
||||
// Publish per repo so a running scan shows new and resolved alerts as they land.
|
||||
c.mu.Lock()
|
||||
c.repos[r.FullName] = r
|
||||
c.mu.Unlock()
|
||||
c.scanDone.Add(1)
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
c.mu.Lock()
|
||||
for _, r := range results {
|
||||
c.repos[r.FullName] = r
|
||||
}
|
||||
c.lastRefresh = start
|
||||
c.lastDur = c.now().Sub(start)
|
||||
c.loaded = true
|
||||
|
||||
@@ -553,3 +553,34 @@ func TestRefreshRepoFailureSkipsRefreshHooks(t *testing.T) {
|
||||
case <-time.After(200 * time.Millisecond):
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshPublishesEachRepoBeforeTheScanEnds(t *testing.T) {
|
||||
release := make(chan struct{})
|
||||
f := &fakeFetcher{fn: func(name string) (model.Repo, error) {
|
||||
if name == "o/slow" {
|
||||
<-release
|
||||
}
|
||||
return model.Repo{FullName: name, Err: ""}, nil
|
||||
}}
|
||||
cfg := &config.Config{Repos: []string{"o/fast", "o/slow"}, RefreshInterval: time.Hour, Concurrency: 2, Thresholds: th()}
|
||||
c := New(f, cfg, slog.New(slog.NewTextHandler(io.Discard, nil)))
|
||||
c.now = func() time.Time { return t0 }
|
||||
done := make(chan struct{})
|
||||
go func() { c.Refresh(context.Background()); close(done) }()
|
||||
deadline := time.Now().Add(2 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
if v := c.View(); len(v.Repos) == 1 && v.Repos[0].FullName == "o/fast" {
|
||||
break
|
||||
}
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
v := c.View()
|
||||
if len(v.Repos) != 1 || v.Repos[0].FullName != "o/fast" || !v.Refreshing || v.Loaded {
|
||||
t.Fatalf("mid-scan view: repos=%d refreshing=%v loaded=%v", len(v.Repos), v.Refreshing, v.Loaded)
|
||||
}
|
||||
close(release)
|
||||
<-done
|
||||
if v := c.View(); len(v.Repos) != 2 || !v.Loaded {
|
||||
t.Fatalf("after scan: repos=%d loaded=%v", len(v.Repos), v.Loaded)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user