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:
+27
-10
@@ -229,21 +229,31 @@ func (r *Registry) List(tenantID, statusFilter, kindFilter, cursor string, limit
|
|||||||
if limit <= 0 {
|
if limit <= 0 {
|
||||||
limit = 50
|
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()
|
r.mu.RLock()
|
||||||
var all []*Job
|
all := make([]*Job, 0, len(r.byID))
|
||||||
for _, j := range r.byID {
|
for _, j := range r.byID {
|
||||||
if j.TenantID != tenantID {
|
if j.TenantID == tenantID {
|
||||||
continue
|
all = append(all, j)
|
||||||
}
|
}
|
||||||
if statusFilter != "" && j.Status != statusFilter {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
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 {
|
if kindFilter != "" && j.Kind != kindFilter {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
all = append(all, j)
|
if statusFilter != "" && j.statusLocked() != statusFilter {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filtered = append(filtered, j)
|
||||||
|
}
|
||||||
|
all = filtered
|
||||||
}
|
}
|
||||||
r.mu.RUnlock()
|
|
||||||
|
|
||||||
sort.Slice(all, func(i, j int) bool {
|
sort.Slice(all, func(i, j int) bool {
|
||||||
return all[i].CreatedAt.After(all[j].CreatedAt)
|
return all[i].CreatedAt.After(all[j].CreatedAt)
|
||||||
@@ -273,9 +283,9 @@ func (r *Registry) CountOtherActiveModuleRefresh(tenantID, excludeJobID string)
|
|||||||
if r == nil {
|
if r == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
// Two-phase: snapshot job pointers under r.mu, then read j.Status under Job.mu.
|
||||||
r.mu.RLock()
|
r.mu.RLock()
|
||||||
defer r.mu.RUnlock()
|
candidates := make([]*Job, 0, 8)
|
||||||
n := 0
|
|
||||||
for _, j := range r.byID {
|
for _, j := range r.byID {
|
||||||
if j.TenantID != tenantID || j.Kind != KindModuleRefresh {
|
if j.TenantID != tenantID || j.Kind != KindModuleRefresh {
|
||||||
continue
|
continue
|
||||||
@@ -283,7 +293,14 @@ func (r *Registry) CountOtherActiveModuleRefresh(tenantID, excludeJobID string)
|
|||||||
if j.ID == excludeJobID {
|
if j.ID == excludeJobID {
|
||||||
continue
|
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++
|
n++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user