Clone different git repos in parallel via per-directory locks (#866)

Old `cloneLock` is a package-level `sync.Mutex` that serialized every action clone across all goroutines, regardless of target directory.
This PR replaces it with a `sync.Map` of per-directory mutexes keyed by `input.Dir`. Same-directory operations still serialize; different directories now clone in parallel.

Reviewed-on: https://gitea.com/gitea/act_runner/pulls/866
Reviewed-by: Lunny Xiao <[email protected]>
Co-authored-by: Zettat123 <[email protected]>
Co-committed-by: Zettat123 <[email protected]>
This commit is contained in:
Zettat123 authored and Lunny Xiao committed 2026-04-28 21:39:41 +00:00
1 parent 801e5cf4d5
commit f09fafcb0a
2 files changed
+71 -3

No files matched your search

+11 -3
View File
@@ -32,12 +32,21 @@ var (
githubHTTPRegex = regexp.MustCompile(`^https?://.*github.com.*/(.+)/(.+?)(?:.git)?$`)
githubSSHRegex = regexp.MustCompile(`github.com[:/](.+)/(.+?)(?:.git)?$`)
cloneLock sync.Mutex
cloneLocks sync.Map // key: clone target directory; value: *sync.Mutex
ErrShortRef = errors.New("short SHA references are not supported")
ErrNoRepo = errors.New("unable to find git repo")
)
// acquireCloneLock returns an unlock function after locking the per-directory mutex for dir.
// Only concurrent operations targeting the same directory are erialized; clones into different directories run in parallel.
func acquireCloneLock(dir string) func() {
v, _ := cloneLocks.LoadOrStore(dir, &sync.Mutex{})
mu := v.(*sync.Mutex)
mu.Lock()
return mu.Unlock
}
type Error struct {
err error
commit string
@@ -301,8 +310,7 @@ func NewGitCloneExecutor(input NewGitCloneExecutorInput) common.Executor {
logger.Infof(" \u2601 git clone '%s' # ref=%s", input.URL, input.Ref)
logger.Debugf(" cloning %s to %s", input.URL, input.Dir)
cloneLock.Lock()
defer cloneLock.Unlock()
defer acquireCloneLock(input.Dir)()
refName := plumbing.ReferenceName("refs/heads/" + input.Ref)
r, err := CloneIfRequired(ctx, refName, input, logger)