Batch and deduplicate action resolution across composite depths#4296
Batch and deduplicate action resolution across composite depths#4296stefanpenner wants to merge 1 commit intoactions:mainfrom
Conversation
9408232 to
397fea0
Compare
Action graph (8 unique actions, depth 3): workflow → leaf-echo, composite-a, composite-b, composite-c composite-a → leaf-echo, leaf-sleep, composite-d composite-b → leaf-echo, leaf-sleep, composite-e composite-c → leaf-echo, composite-d, composite-e composite-d → leaf-echo, leaf-sleep, composite-f composite-e → leaf-echo, leaf-sleep, composite-f composite-f → leaf-echo, leaf-sleep Without batching: ~15-20 resolve API calls (one per composite per depth) With actions/runner#4296: ~3-4 calls (one batch per depth level) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Action graph (50 unique actions, 5 depth levels): workflow → 10x L1 composites + 5 leaves (15 top-level) L1-NN → 1 leaf + 3 L2 composites (heavy cross-referencing) L2-NN → 1 leaf + 3 L3 composites L3-NN → 2 leaves + 2 L4 composites L4-NN → 3 leaves Without batching/dedup: ~301 resolve API calls With actions/runner#4296: ~4 calls (75x reduction) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR optimizes action resolution in composite action trees by batching and deduplicating API calls across recursion depths. Instead of resolving sub-actions one composite at a time (N API calls), it collects all sub-actions at each depth level and resolves them in a single batch call, with a cross-depth cache to avoid re-resolving the same action. It also defers pre/post step registration until after recursion completes.
Changes:
- Introduce a stack-local
resolvedDownloadInfoscache to deduplicate action resolution across composite depths, and a newResolveNewActionsAsynchelper that skips already-cached actions - Collect composite sub-actions into a
nextLevellist and batch-resolve them before recursing per parent group - Defer pre/post step registration to after recursion so that
HasPre/HasPostreflect the full subtree
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/Runner.Worker/ActionManager.cs |
Core optimization: adds resolution cache, batch pre-resolution of next-level actions, deferred pre/post registration, and new ResolveNewActionsAsync helper |
src/Test/L0/Worker/ActionManagerL0.cs |
5 new L0 tests covering batching, cross-depth dedup, multi-top-level, nested containers, and parallel downloads |
You can also share your feedback on Copilot code review. Take the survey.
There was a problem hiding this comment.
Pull request overview
This PR optimizes action resolution in the GitHub Actions runner by introducing batching and cross-depth deduplication for composite action resolution. Instead of making individual API calls per composite action at each recursion depth, sub-actions from all composites at the same depth are collected and resolved in a single batch API call. A stack-local cache ensures the same owner/repo@ref is only resolved once even if it appears at multiple depths in the composite tree. Pre/post step registration is deferred until after recursion to ensure HasPre/HasPost reflect the full subtree.
Changes:
- Added a case-insensitive
resolvedDownloadInfosdictionary that caches resolved action download info across recursion depths, with aResolveNewActionsAsynchelper that skips already-cached actions - Refactored
PrepareActionsRecursiveAsyncto collect composite sub-actions into anextLevellist, batch-resolve them in one API call, then recurse per-parent group — moving pre/post step registration after recursion - Added 5 new L0 tests covering batching, cross-depth dedup, multiple top-level actions, nested containers, and parallel downloads
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/Runner.Worker/ActionManager.cs | Core optimization: batch resolution cache, ResolveNewActionsAsync helper, deferred pre/post registration |
| src/Test/L0/Worker/ActionManagerL0.cs | 5 new tests validating batching, deduplication, multi-action, nested container, and parallel download scenarios |
You can also share your feedback on Copilot code review. Take the survey.
6e27f5a to
0aa89ce
Compare
Thread a cache through PrepareActionsRecursiveAsync so the same action is resolved at most once regardless of depth. Collect sub-actions from all sibling composites and resolve them in one API call instead of one per composite. ~30-composite internal workflow went from ~20 resolve calls to 3-4. Fixes actions#3731 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
0aa89ce to
5bcd72f
Compare
Summary
Internal workflow with ~30 composites: ~20 resolve API calls → 3-4. Also reduces 429s (#4232).
Fixes #3731
Other possibilities
Smoke test results
Tested with a self-hosted runner built from this branch vs stock (
main), using a 50-action composite tree across 6 repos with 5 depth levels.Action graph:
Results (run)
main)owner/repo@refnever re-resolved across depthsEarlier run (single-repo, same-ref tree)
Run: 311 → 1 resolve calls (all 50 actions shared the same
owner/repo@reflookup key, so the cache eliminated every call after the first).Test plan
🤖 Generated with Claude Code