From f9b9ee93cd32839fc150efc44eb183923eda56b0 Mon Sep 17 00:00:00 2001 From: Amin Salarkia Date: Tue, 17 Dec 2024 14:43:21 +0100 Subject: [PATCH] fix(cd-service): less calls to db select app in releasetrains (#2176) Ref: SRX-625RAW --- pkg/db/db.go | 66 +++++++++++++++++++ .../cd-service/pkg/repository/repository.go | 27 ++++++++ .../cd-service/pkg/repository/transformer.go | 21 ++++-- 3 files changed, 109 insertions(+), 5 deletions(-) diff --git a/pkg/db/db.go b/pkg/db/db.go index 898511daa..db8685f8c 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -1642,6 +1642,35 @@ func (h *DBHandler) DBSelectApp(ctx context.Context, tx *sql.Tx, appName string) return h.processAppsRow(ctx, rows, err) } +func (h *DBHandler) DBSelectAllAppsMetadata(ctx context.Context, tx *sql.Tx) ([]*DBAppWithMetaData, error) { + span, ctx := tracer.StartSpanFromContext(ctx, "DBSelectAllAppsMetadata") + defer span.Finish() + selectQuery := h.AdaptQuery(` +SELECT + apps.appname, + apps.stateChange, + apps.metadata +FROM ( + SELECT + MAX(version) AS latest, + appname +FROM + "apps" +GROUP BY + appName +) AS latest +JOIN + apps AS apps +ON +latest.latest=apps.version +AND latest.appname=apps.appname + `) + span.SetTag("query", selectQuery) + rows, err := tx.QueryContext(ctx, selectQuery) + + return h.processAppsRows(ctx, rows, err) +} + func (h *DBHandler) DBSelectAppAtTimestamp(ctx context.Context, tx *sql.Tx, appName string, ts time.Time) (*DBAppWithMetaData, error) { span, ctx := tracer.StartSpanFromContext(ctx, "DBSelectAppAtTimestamp") defer span.Finish() @@ -1662,6 +1691,43 @@ func (h *DBHandler) DBSelectAppAtTimestamp(ctx context.Context, tx *sql.Tx, appN return h.processAppsRow(ctx, rows, err) } +func (h *DBHandler) processAppsRows(ctx context.Context, rows *sql.Rows, err error) ([]*DBAppWithMetaData, error) { + if err != nil { + return nil, fmt.Errorf("could not query apps table from DB. Error: %w\n", err) + } + defer func(rows *sql.Rows) { + err := rows.Close() + if err != nil { + logger.FromContext(ctx).Sugar().Warnf("row could not be closed: %v", err) + } + }(rows) + var result []*DBAppWithMetaData + for rows.Next() { + //exhaustruct:ignore + var row = &DBAppWithMetaData{} + var metadataStr string + err := rows.Scan(&row.App, &row.StateChange, &metadataStr) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, nil + } + return nil, fmt.Errorf("Error scanning apps row from DB. Error: %w\n", err) + } + var metaData = DBAppMetaData{Team: ""} + err = json.Unmarshal(([]byte)(metadataStr), &metaData) + if err != nil { + return nil, fmt.Errorf("Error during json unmarshal of apps. Error: %w. Data: %s\n", err, metadataStr) + } + row.Metadata = metaData + result = append(result, row) + } + err = closeRows(rows) + if err != nil { + return nil, err + } + return result, nil +} + func (h *DBHandler) processAppsRow(ctx context.Context, rows *sql.Rows, err error) (*DBAppWithMetaData, error) { if err != nil { return nil, fmt.Errorf("could not query apps table from DB. Error: %w\n", err) diff --git a/services/cd-service/pkg/repository/repository.go b/services/cd-service/pkg/repository/repository.go index c30958d23..0b49ea85b 100644 --- a/services/cd-service/pkg/repository/repository.go +++ b/services/cd-service/pkg/repository/repository.go @@ -3216,6 +3216,33 @@ func (s *State) GetApplicationTeamOwner(ctx context.Context, transaction *sql.Tx } } +func (s *State) GetAllApplicationsTeamOwner(ctx context.Context, transaction *sql.Tx) (map[string]string, error) { + result := make(map[string]string) + if s.DBHandler.ShouldUseOtherTables() { + apps, err := s.DBHandler.DBSelectAllAppsMetadata(ctx, transaction) + if err != nil { + return result, fmt.Errorf("could not get team of all apps: %w", err) + } + for _, app := range apps { + result[app.App] = app.Metadata.Team + } + return result, nil + } else { + apps, err := s.GetApplications(ctx, transaction) + if err != nil { + return result, err + } + for _, app := range apps { + teamOwner, err := s.GetApplicationTeamOwnerFromManifest(app) + if err != nil { + return result, err + } + result[app] = teamOwner + } + return result, nil + } +} + func (s *State) GetApplicationTeamOwnerAtTimestamp(ctx context.Context, transaction *sql.Tx, application string, ts time.Time) (string, error) { if s.DBHandler.ShouldUseOtherTables() { app, err := s.DBHandler.DBSelectAppAtTimestamp(ctx, transaction, application, ts) diff --git a/services/cd-service/pkg/repository/transformer.go b/services/cd-service/pkg/repository/transformer.go index 2d811cef8..698f1c801 100644 --- a/services/cd-service/pkg/repository/transformer.go +++ b/services/cd-service/pkg/repository/transformer.go @@ -3809,16 +3809,27 @@ func (c *envReleaseTrain) prognosis( } } span.SetTag("ConsideredApps", len(apps)) + allTeams, err := state.GetAllApplicationsTeamOwner(ctx, transaction) + if err != nil { + return ReleaseTrainEnvironmentPrognosis{ + SkipCause: nil, + Error: err, + Locks: nil, + AppsPrognoses: nil, + } + } for _, appName := range apps { if c.Parent.Team != "" { - if team, err := state.GetApplicationTeamOwner(ctx, transaction, appName); err != nil { + team, ok := allTeams[appName] + if !ok { return ReleaseTrainEnvironmentPrognosis{ SkipCause: nil, - Error: err, + Error: fmt.Errorf("team for app %s not found", appName), Locks: nil, AppsPrognoses: nil, } - } else if c.Parent.Team != team { + } + if c.Parent.Team != team { continue } } @@ -3947,9 +3958,9 @@ func (c *envReleaseTrain) prognosis( } } - teamName, err := state.GetTeamName(ctx, transaction, appName) + teamName, ok := allTeams[appName] - if err == nil { //IF we find information for team + if ok { //IF we find information for team err := state.checkUserPermissions(ctx, transaction, c.Env, "*", auth.PermissionDeployReleaseTrain, teamName, c.Parent.RBACConfig, true)