feat(api): 集群列表读改走 informer 缓存,审核队列、我的提交与备份列表改为服务端分页筛选并一次批量查构建,面板三页跟进
This commit is contained in:
41 files changed
+1642
-295
No files matched your search
@@ -198,6 +198,9 @@ type Store interface {
|
||||
CreateBuild(ctx context.Context, b *Build) error
|
||||
// GetBuild loads one build, or ErrNotFound.
|
||||
GetBuild(ctx context.Context, id string) (*Build, error)
|
||||
// GetBuilds loads the builds among ids that exist, in no particular order and
|
||||
// without their Dockerfile — one query for a whole list's worth of lookups.
|
||||
GetBuilds(ctx context.Context, ids []string) ([]Build, error)
|
||||
// SetBuildJob records the Job name and advances status to building.
|
||||
SetBuildJob(ctx context.Context, id, jobName string) error
|
||||
// FinishBuild sets a terminal status, an optional error, and finished_at.
|
||||
@@ -519,6 +522,24 @@ func (b *Builder) Get(ctx context.Context, id string) (*Build, error) {
|
||||
return b.Store.GetBuild(ctx, id)
|
||||
}
|
||||
|
||||
// GetMany returns the builds among ids that exist, keyed by id, read as stored
|
||||
// (no reconcile) and without their Dockerfile. An id with no row is absent from
|
||||
// the map.
|
||||
func (b *Builder) GetMany(ctx context.Context, ids []string) (map[string]Build, error) {
|
||||
out := make(map[string]Build, len(ids))
|
||||
if len(ids) == 0 {
|
||||
return out, nil
|
||||
}
|
||||
builds, err := b.Store.GetBuilds(ctx, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, bld := range builds {
|
||||
out[bld.ID] = bld
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ListBuilds pages the build history for the admin panel, so every admin sees
|
||||
// every build (and can cancel a running one) from any browser. It reads rows as
|
||||
// stored: reconcileBuilds advances them in the background, and GET
|
||||
|
||||
@@ -25,6 +25,8 @@ type fakeStore struct {
|
||||
removeErr error
|
||||
createErr error
|
||||
listOpts ListOpts
|
||||
|
||||
getManyCalls int
|
||||
}
|
||||
|
||||
func newFakeStore() *fakeStore {
|
||||
@@ -49,6 +51,17 @@ func (f *fakeStore) GetBuild(_ context.Context, id string) (*Build, error) {
|
||||
return &cp, nil
|
||||
}
|
||||
|
||||
func (f *fakeStore) GetBuilds(_ context.Context, ids []string) ([]Build, error) {
|
||||
f.getManyCalls++
|
||||
var out []Build
|
||||
for _, id := range ids {
|
||||
if b, ok := f.builds[id]; ok {
|
||||
out = append(out, *b)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (f *fakeStore) SetBuildJob(_ context.Context, id, jobName string) error {
|
||||
b, ok := f.builds[id]
|
||||
if !ok {
|
||||
@@ -776,3 +789,28 @@ func TestListBuildsBoundsThePage(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetMany answers a whole list's lookups with one store read, keys the rows by
|
||||
// id, leaves an unknown id out, and asks nothing of the store for an empty list.
|
||||
func TestGetManyIsOneRead(t *testing.T) {
|
||||
b, st, _ := newBuilder()
|
||||
st.builds["bld-1"] = &Build{ID: "bld-1", Status: StatusFailed, Error: "scan found a CRITICAL CVE"}
|
||||
st.builds["bld-2"] = &Build{ID: "bld-2", Status: StatusSucceeded}
|
||||
got, err := b.GetMany(context.Background(), []string{"bld-1", "bld-2", "bld-gone"})
|
||||
if err != nil {
|
||||
t.Fatalf("GetMany: %v", err)
|
||||
}
|
||||
if st.getManyCalls != 1 {
|
||||
t.Fatalf("store reads = %d, want 1", st.getManyCalls)
|
||||
}
|
||||
if len(got) != 2 || got["bld-1"].Status != StatusFailed || got["bld-1"].Error != "scan found a CRITICAL CVE" ||
|
||||
got["bld-2"].Status != StatusSucceeded {
|
||||
t.Fatalf("GetMany = %+v, want bld-1 failed and bld-2 succeeded", got)
|
||||
}
|
||||
if _, ok := got["bld-gone"]; ok {
|
||||
t.Fatal("an unknown id must be absent")
|
||||
}
|
||||
if got, err := b.GetMany(context.Background(), nil); err != nil || len(got) != 0 || st.getManyCalls != 1 {
|
||||
t.Fatalf("GetMany(nil) = %v, %v with %d reads; want an empty map and no read", got, err, st.getManyCalls)
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,16 @@ func (s *PGStore) GetBuild(ctx context.Context, id string) (*Build, error) {
|
||||
return s.scanBuild(s.db.QueryRowContext(ctx, q, id))
|
||||
}
|
||||
|
||||
func (s *PGStore) GetBuilds(ctx context.Context, ids []string) ([]Build, error) {
|
||||
rows, err := s.db.QueryContext(ctx, `SELECT id, image_ref, status, '', context_ref, base_image,
|
||||
requested_by, job_name, log_ref, error, created_at, finished_at, context_digest
|
||||
FROM image_builds WHERE id = ANY($1::text[])`, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return scanBuilds(rows)
|
||||
}
|
||||
|
||||
func (s *PGStore) scanBuild(row *sql.Row) (*Build, error) {
|
||||
var (
|
||||
b Build
|
||||
|
||||
Reference in new issue
Block a user