refactor: optimize job listing and counting logic for concurrency safety. Separate tenant filtering and status checks to reduce lock contention, improving performance and ensuring accurate job status retrieval.
CI / changes (push) Successful in 14s
CI / openapi (push) Has been skipped
CI / go (push) Successful in 1m12s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, , evobgp-web) (push) Has been skipped
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, evobgp-all, evobgp-web-all) (push) Has been skipped
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Successful in 20s
CI / docker-go-prime (push) Successful in 29s
CI / docker-go (deploy/docker/evobgp-agent/Dockerfile, , evobgp-agent) (push) Successful in 1m19s
CI / docker-go (evobgp-all, 1, deploy/docker/gobinary/Dockerfile, , evobgp-all) (push) Successful in 2m54s
CI / docker-go (evobgp-api, 1, deploy/docker/gobinary/Dockerfile, , evobgp-api) (push) Successful in 1m49s
CI / docker-go (evobgp-deploy, 0, deploy/docker/gobinary/Dockerfile, , evobgp-deploy) (push) Successful in 1m47s
CI / docker-go (evobgp-ingest, 0, deploy/docker/gobinary/Dockerfile, , evobgp-ingest) (push) Successful in 1m45s
CI / docker-go (evobgp-node, 0, deploy/docker/gobinary/Dockerfile, , evobgp-node) (push) Successful in 1m14s
CI / docker-go (evobgp-render, 0, deploy/docker/gobinary/Dockerfile, , evobgp-render) (push) Successful in 1m30s
CI / docker-go (evobgp-scheduler, 0, deploy/docker/gobinary/Dockerfile, , evobgp-scheduler) (push) Successful in 1m26s
CI / changes (push) Successful in 14s
CI / openapi (push) Has been skipped
CI / go (push) Successful in 1m12s
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, , evobgp-web) (push) Has been skipped
CI / docker-web (deploy/docker/evobgp-web/Dockerfile, evobgp-all, evobgp-web-all) (push) Has been skipped
CI / docker-bird (push) Has been skipped
CI / bird2 (push) Successful in 20s
CI / docker-go-prime (push) Successful in 29s
CI / docker-go (deploy/docker/evobgp-agent/Dockerfile, , evobgp-agent) (push) Successful in 1m19s
CI / docker-go (evobgp-all, 1, deploy/docker/gobinary/Dockerfile, , evobgp-all) (push) Successful in 2m54s
CI / docker-go (evobgp-api, 1, deploy/docker/gobinary/Dockerfile, , evobgp-api) (push) Successful in 1m49s
CI / docker-go (evobgp-deploy, 0, deploy/docker/gobinary/Dockerfile, , evobgp-deploy) (push) Successful in 1m47s
CI / docker-go (evobgp-ingest, 0, deploy/docker/gobinary/Dockerfile, , evobgp-ingest) (push) Successful in 1m45s
CI / docker-go (evobgp-node, 0, deploy/docker/gobinary/Dockerfile, , evobgp-node) (push) Successful in 1m14s
CI / docker-go (evobgp-render, 0, deploy/docker/gobinary/Dockerfile, , evobgp-render) (push) Successful in 1m30s
CI / docker-go (evobgp-scheduler, 0, deploy/docker/gobinary/Dockerfile, , evobgp-scheduler) (push) Successful in 1m26s
This commit is contained in:
+30
-13
@@ -229,22 +229,32 @@ func (r *Registry) List(tenantID, statusFilter, kindFilter, cursor string, limit
|
||||
if limit <= 0 {
|
||||
limit = 50
|
||||
}
|
||||
// Build candidate set under r.mu, but read mutable status fields (j.Status) outside
|
||||
// of r.mu so we don't race with Job.mu-protected writes (MarkRunning/Succeed/Fail).
|
||||
r.mu.RLock()
|
||||
var all []*Job
|
||||
all := make([]*Job, 0, len(r.byID))
|
||||
for _, j := range r.byID {
|
||||
if j.TenantID != tenantID {
|
||||
continue
|
||||
if j.TenantID == tenantID {
|
||||
all = append(all, j)
|
||||
}
|
||||
if statusFilter != "" && j.Status != statusFilter {
|
||||
continue
|
||||
}
|
||||
if kindFilter != "" && j.Kind != kindFilter {
|
||||
continue
|
||||
}
|
||||
all = append(all, j)
|
||||
}
|
||||
r.mu.RUnlock()
|
||||
|
||||
// Apply filters outside of r.mu to synchronize with Job.mu.
|
||||
if statusFilter != "" || kindFilter != "" {
|
||||
filtered := all[:0]
|
||||
for _, j := range all {
|
||||
if kindFilter != "" && j.Kind != kindFilter {
|
||||
continue
|
||||
}
|
||||
if statusFilter != "" && j.statusLocked() != statusFilter {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, j)
|
||||
}
|
||||
all = filtered
|
||||
}
|
||||
|
||||
sort.Slice(all, func(i, j int) bool {
|
||||
return all[i].CreatedAt.After(all[j].CreatedAt)
|
||||
})
|
||||
@@ -273,9 +283,9 @@ func (r *Registry) CountOtherActiveModuleRefresh(tenantID, excludeJobID string)
|
||||
if r == nil {
|
||||
return 0
|
||||
}
|
||||
// Two-phase: snapshot job pointers under r.mu, then read j.Status under Job.mu.
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
n := 0
|
||||
candidates := make([]*Job, 0, 8)
|
||||
for _, j := range r.byID {
|
||||
if j.TenantID != tenantID || j.Kind != KindModuleRefresh {
|
||||
continue
|
||||
@@ -283,7 +293,14 @@ func (r *Registry) CountOtherActiveModuleRefresh(tenantID, excludeJobID string)
|
||||
if j.ID == excludeJobID {
|
||||
continue
|
||||
}
|
||||
if j.Status == StatusQueued || j.Status == StatusRunning {
|
||||
candidates = append(candidates, j)
|
||||
}
|
||||
r.mu.RUnlock()
|
||||
|
||||
n := 0
|
||||
for _, j := range candidates {
|
||||
st := j.statusLocked()
|
||||
if st == StatusQueued || st == StatusRunning {
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user