Skip to content

Commit 5fc8493

Browse files
author
Sonarly Claude Code
committed
fix: batch workflow public check in CAS mapping FindByDigest to avoid N+1 queries
https://sonarly.com/issue/16915?type=bug The `FindByDigest` method in the CAS mapping data layer executes 2 sequential database queries per CAS mapping result (workflow_run + workflow) inside a loop, creating an N+1 query pattern that causes context deadline exceeded errors when a digest has many mappings or the database is under load. Fix: Replaced the N+1 query pattern in `FindByDigest` with a new `batchIsPublic` method that resolves the public status of all CAS mappings in exactly 2 batched queries instead of 2*N sequential queries. **Before:** For each CAS mapping returned by `FindByDigest`, `IsPublic` was called individually, executing 2 sequential DB queries per mapping (one for `workflow_run`, one for `workflow`). With N mappings, this resulted in 1 + 2N total queries, all sequential within the request context's deadline. **After:** `batchIsPublic` collects all unique workflow run IDs, fetches them in a single `WHERE id IN (...)` query, then fetches all referenced workflows in another single query. Total: 3 queries regardless of mapping count. The behavioral contract is preserved: - Mappings with nil `workflow_run_id` → `public = false` - Mappings whose workflow run or workflow has been deleted → skipped (same as the previous `ent.IsNotFound → continue` behavior) - The single-lookup `IsPublic` method is retained for `findByID` which operates on a single mapping No interface, type, or schema changes. No auto-generated files modified.
1 parent e93bf92 commit 5fc8493

1 file changed

Lines changed: 83 additions & 7 deletions

File tree

app/controlplane/pkg/data/casmapping.go

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,18 @@ func (r *CASMappingRepo) FindByDigest(ctx context.Context, digest string) ([]*bi
7878
return nil, fmt.Errorf("failed to list cas mappings: %w", err)
7979
}
8080

81+
// Batch-resolve public status for all mappings to avoid N+1 queries
82+
publicByRunID, err := r.batchIsPublic(ctx, r.data.DB, mappings)
83+
if err != nil {
84+
return nil, fmt.Errorf("failed to check if workflows are public: %w", err)
85+
}
86+
8187
res := make([]*biz.CASMapping, 0, len(mappings))
8288
for _, m := range mappings {
83-
public, err := r.IsPublic(ctx, r.data.DB, m.WorkflowRunID)
84-
if err != nil {
85-
if ent.IsNotFound(err) {
86-
continue
87-
}
88-
89-
return nil, fmt.Errorf("failed to check if workflow is public: %w", err)
89+
public, ok := publicByRunID[m.WorkflowRunID]
90+
if !ok {
91+
// workflow run or workflow was not found, skip this mapping
92+
continue
9093
}
9194
r, err := entCASMappingToBiz(m, public)
9295
if err != nil {
@@ -122,6 +125,79 @@ func (r *CASMappingRepo) findByID(ctx context.Context, id uuid.UUID) (*biz.CASMa
122125
return entCASMappingToBiz(backend, public)
123126
}
124127

128+
// batchIsPublic resolves the public status for all mappings in two batched queries
129+
// instead of 2*N individual queries. Returns a map of workflow_run_id -> public flag.
130+
// Mappings with nil workflow_run_id are included as false.
131+
// Mappings whose workflow run or workflow was deleted are omitted from the result.
132+
func (r *CASMappingRepo) batchIsPublic(ctx context.Context, client *ent.Client, mappings []*ent.CASMapping) (map[uuid.UUID]bool, error) {
133+
result := make(map[uuid.UUID]bool, len(mappings))
134+
135+
// Collect unique non-nil workflow run IDs
136+
runIDs := make([]uuid.UUID, 0, len(mappings))
137+
for _, m := range mappings {
138+
if m.WorkflowRunID == uuid.Nil {
139+
result[m.WorkflowRunID] = false
140+
continue
141+
}
142+
runIDs = append(runIDs, m.WorkflowRunID)
143+
}
144+
145+
if len(runIDs) == 0 {
146+
return result, nil
147+
}
148+
149+
// Batch query: get all workflow runs with their workflow IDs
150+
runs, err := client.WorkflowRun.Query().
151+
Where(workflowrun.IDIn(runIDs...)).
152+
Select(workflowrun.FieldID, workflowrun.FieldWorkflowID).
153+
All(ctx)
154+
if err != nil {
155+
return nil, fmt.Errorf("failed to batch get workflow runs: %w", err)
156+
}
157+
158+
// Collect unique workflow IDs and build runID -> workflowID map
159+
runToWorkflow := make(map[uuid.UUID]uuid.UUID, len(runs))
160+
workflowIDs := make([]uuid.UUID, 0, len(runs))
161+
seen := make(map[uuid.UUID]bool, len(runs))
162+
for _, wr := range runs {
163+
runToWorkflow[wr.ID] = wr.WorkflowID
164+
if !seen[wr.WorkflowID] {
165+
workflowIDs = append(workflowIDs, wr.WorkflowID)
166+
seen[wr.WorkflowID] = true
167+
}
168+
}
169+
170+
if len(workflowIDs) == 0 {
171+
return result, nil
172+
}
173+
174+
// Batch query: get all workflows with their public flag
175+
workflows, err := client.Workflow.Query().
176+
Where(workflow.IDIn(workflowIDs...)).
177+
Select(workflow.FieldID, workflow.FieldPublic).
178+
All(ctx)
179+
if err != nil {
180+
return nil, fmt.Errorf("failed to batch get workflows: %w", err)
181+
}
182+
183+
workflowPublic := make(map[uuid.UUID]bool, len(workflows))
184+
for _, w := range workflows {
185+
workflowPublic[w.ID] = w.Public
186+
}
187+
188+
// Build the final map: runID -> public
189+
for runID, wfID := range runToWorkflow {
190+
if public, ok := workflowPublic[wfID]; ok {
191+
result[runID] = public
192+
}
193+
// If the workflow is not found, omit the entry so the mapping gets skipped
194+
}
195+
196+
return result, nil
197+
}
198+
199+
// IsPublic checks if the workflow associated with a workflow run is public.
200+
// Used for single-mapping lookups (e.g. findByID).
125201
func (r *CASMappingRepo) IsPublic(ctx context.Context, client *ent.Client, runID uuid.UUID) (bool, error) {
126202
// If the workflow run id is not set, the mapping is not public
127203
if runID == uuid.Nil {

0 commit comments

Comments
 (0)