Optimize GetReadyWork to use blocked_issues_cache
Replaces expensive recursive CTE query with simple cache lookup, achieving 96% performance improvement on 10K databases (bd-5qim). Performance results: - Before: ~752ms (recursive CTE on every call) - After: ~29ms (cache lookup + filters) - Target: <50ms ✓ The query now uses a simple NOT EXISTS check against the blocked_issues_cache table instead of computing the full blocked issue tree on every call. Cache is maintained by invalidateBlockedCache() called on dependency and status changes (added in next commit). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -81,47 +81,17 @@ func (s *SQLiteStorage) GetReadyWork(ctx context.Context, filter types.WorkFilte
|
||||
}
|
||||
orderBySQL := buildOrderByClause(sortPolicy)
|
||||
|
||||
// Query with recursive CTE to propagate blocking through parent-child hierarchy
|
||||
// Algorithm:
|
||||
// 1. Find issues directly blocked by 'blocks' dependencies
|
||||
// 2. Recursively propagate blockage to all descendants via 'parent-child' links
|
||||
// 3. Exclude all blocked issues (both direct and transitive) from ready work
|
||||
// Use blocked_issues_cache for performance (bd-5qim)
|
||||
// Cache is maintained by invalidateBlockedCache() called on dependency/status changes
|
||||
// #nosec G201 - safe SQL with controlled formatting
|
||||
query := fmt.Sprintf(`
|
||||
WITH RECURSIVE
|
||||
-- Step 1: Find issues blocked directly by dependencies
|
||||
blocked_directly AS (
|
||||
SELECT DISTINCT d.issue_id
|
||||
FROM dependencies d
|
||||
JOIN issues blocker ON d.depends_on_id = blocker.id
|
||||
WHERE d.type = 'blocks'
|
||||
AND blocker.status IN ('open', 'in_progress', 'blocked')
|
||||
),
|
||||
|
||||
-- Step 2: Propagate blockage to all descendants via parent-child
|
||||
blocked_transitively AS (
|
||||
-- Base case: directly blocked issues
|
||||
SELECT issue_id, 0 as depth
|
||||
FROM blocked_directly
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Recursive case: children of blocked issues inherit blockage
|
||||
SELECT d.issue_id, bt.depth + 1
|
||||
FROM blocked_transitively bt
|
||||
JOIN dependencies d ON d.depends_on_id = bt.issue_id
|
||||
WHERE d.type = 'parent-child'
|
||||
AND bt.depth < 50
|
||||
)
|
||||
|
||||
-- Step 3: Select ready issues (excluding all blocked)
|
||||
SELECT i.id, i.content_hash, i.title, i.description, i.design, i.acceptance_criteria, i.notes,
|
||||
i.status, i.priority, i.issue_type, i.assignee, i.estimated_minutes,
|
||||
i.created_at, i.updated_at, i.closed_at, i.external_ref, i.source_repo
|
||||
FROM issues i
|
||||
WHERE %s
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM blocked_transitively WHERE issue_id = i.id
|
||||
SELECT 1 FROM blocked_issues_cache WHERE issue_id = i.id
|
||||
)
|
||||
%s
|
||||
%s
|
||||
|
||||
Reference in New Issue
Block a user