From 7d87036471241c78aabbef2e9415d883c15c3103 Mon Sep 17 00:00:00 2001 From: "A. Ottr" Date: Fri, 23 Jan 2026 21:14:00 +0100 Subject: [PATCH] feat: add concurrency to deployments Signed-off-by: A. Ottr --- config.yml.example | 1 + main.go | 42 ++++++++++++++++++++++++++++++------------ sync.go | 9 +++++++-- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/config.yml.example b/config.yml.example index ef09a39..a14c4a8 100644 --- a/config.yml.example +++ b/config.yml.example @@ -1,4 +1,5 @@ # Configuration file for compose-sync repo_url: "git@github.com:user/compose-repo.git" # Optional: URL for cloning (not used if repo_path already exists) repo_path: "/path/to/local/repo" # Required: Local path to the git repository +concurrency: 3 # Optional: Number of concurrent deployments (default: 3) diff --git a/main.go b/main.go index 1cfd1f8..9285e30 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" "slices" + "sync" ) func main() { @@ -79,17 +80,34 @@ func main() { return } - // Deploy each stack - for _, stack := range stacksToDeploy { - composePath := filepath.Join(cfg.RepoPath, "stacks", stack, "compose.yml") - if _, err := os.Stat(composePath); os.IsNotExist(err) { - composePath = filepath.Join(cfg.RepoPath, "stacks", stack, "compose.yaml") - } - fmt.Printf("Deploying stack: %s\n", stack) - if err := deployStack(composePath); err != nil { - log.Printf("Failed to deploy stack %s: %v", stack, err) - continue - } - fmt.Printf("Successfully deployed stack: %s\n", stack) + deployStacks(cfg.RepoPath, stacksToDeploy, cfg.Concurrency) +} + +func deployStacks(repoPath string, stacks []string, concurrency int) { + // Create a semaphore channel to limit concurrency + semaphore := make(chan struct{}, concurrency) + var wg sync.WaitGroup + + for _, stack := range stacks { + wg.Add(1) + go func(stack string) { + defer wg.Done() + + semaphore <- struct{}{} + defer func() { <-semaphore }() + + composePath := filepath.Join(repoPath, "stacks", stack, "compose.yml") + if _, err := os.Stat(composePath); os.IsNotExist(err) { + composePath = filepath.Join(repoPath, "stacks", stack, "compose.yaml") + } + + fmt.Printf("Deploying stack: %s\n", stack) + if err := deployStack(composePath); err != nil { + log.Printf("Failed to deploy stack %s: %v", stack, err) + return + } + fmt.Printf("Successfully deployed stack: %s\n", stack) + }(stack) } + wg.Wait() } diff --git a/sync.go b/sync.go index d32fd9e..fa7483c 100644 --- a/sync.go +++ b/sync.go @@ -13,8 +13,9 @@ import ( ) type config struct { - RepoURL string `yaml:"repo_url"` - RepoPath string `yaml:"repo_path"` + RepoURL string `yaml:"repo_url"` + RepoPath string `yaml:"repo_path"` + Concurrency int `yaml:"concurrency"` } func loadConfig(path string) (*config, error) { @@ -32,6 +33,10 @@ func loadConfig(path string) (*config, error) { return nil, fmt.Errorf("repo_path is required in config") } + if cfg.Concurrency <= 0 { + cfg.Concurrency = 3 // Safe default for Docker + } + return &cfg, nil } -- 2.51.2