Skip to content

Commit

Permalink
introduce --parallel to limit concurrent engine calls
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolas De Loof <[email protected]>
  • Loading branch information
ndeloof committed Nov 30, 2022
1 parent ed38fe0 commit 9bc188b
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 8 deletions.
13 changes: 9 additions & 4 deletions cmd/compose/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,11 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command {

opts := projectOptions{}
var (
ansi string
noAnsi bool
verbose bool
version bool
ansi string
noAnsi bool
verbose bool
version bool
parallel int
)
c := &cobra.Command{
Short: "Docker Compose",
Expand Down Expand Up @@ -325,6 +326,9 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command {
opts.ProjectDir = opts.WorkDir
fmt.Fprint(os.Stderr, aec.Apply("option '--workdir' is DEPRECATED at root level! Please use '--project-directory' instead.\n", aec.RedF))
}
if parallel > 0 {
backend.MaxConcurrency(parallel)
}
return nil
},
}
Expand Down Expand Up @@ -370,6 +374,7 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command {
)

c.Flags().StringVar(&ansi, "ansi", "auto", `Control when to print ANSI control characters ("never"|"always"|"auto")`)
c.Flags().IntVar(&parallel, "parallel", -1, `Control max parallelism (unlimited)`)
c.Flags().BoolVarP(&version, "version", "v", false, "Show the Docker Compose version information")
c.Flags().MarkHidden("version") //nolint:errcheck
c.Flags().BoolVar(&noAnsi, "no-ansi", false, `Do not print ANSI control characters (DEPRECATED)`)
Expand Down
1 change: 1 addition & 0 deletions docs/reference/compose.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Docker Compose
| `--compatibility` | | | Run compose in backward compatibility mode |
| `--env-file` | `string` | | Specify an alternate environment file. |
| `-f`, `--file` | `stringArray` | | Compose configuration files |
| `--parallel` | `int` | `-1` | Control max parallelism (unlimited) |
| `--profile` | `stringArray` | | Specify a profile to enable |
| `--project-directory` | `string` | | Specify an alternate working directory
(default: the path of the, first specified, Compose file) |
Expand Down
10 changes: 10 additions & 0 deletions docs/reference/docker_compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,16 @@ options:
experimentalcli: false
kubernetes: false
swarm: false
- option: parallel
value_type: int
default_value: "-1"
description: Control max parallelism (unlimited)
deprecated: false
hidden: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
- option: profile
value_type: stringArray
default_value: '[]'
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ type Service interface {
Port(ctx context.Context, projectName string, service string, port int, options PortOptions) (string, int, error)
// Images executes the equivalent of a `compose images`
Images(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
// MaxConcurrency defines upper limit for concurrent operations against engine API
MaxConcurrency(parallel int)
}

// BuildOptions group options of the Build API
Expand Down
6 changes: 6 additions & 0 deletions pkg/api/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type ServiceProxy struct {
EventsFn func(ctx context.Context, project string, options EventsOptions) error
PortFn func(ctx context.Context, project string, service string, port int, options PortOptions) (string, int, error)
ImagesFn func(ctx context.Context, projectName string, options ImagesOptions) ([]ImageSummary, error)
MaxConcurrencyFn func(parallel int)
interceptors []Interceptor
}

Expand Down Expand Up @@ -87,6 +88,7 @@ func (s *ServiceProxy) WithService(service Service) *ServiceProxy {
s.EventsFn = service.Events
s.PortFn = service.Port
s.ImagesFn = service.Images
s.MaxConcurrencyFn = service.MaxConcurrency
return s
}

Expand Down Expand Up @@ -308,3 +310,7 @@ func (s *ServiceProxy) Images(ctx context.Context, project string, options Image
}
return s.ImagesFn(ctx, project, options)
}

func (s *ServiceProxy) MaxConcurrency(i int) {
s.MaxConcurrencyFn(i)
}
13 changes: 9 additions & 4 deletions pkg/compose/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import (
"io"
"strings"

"gopkg.in/yaml.v2"

"github.com/compose-spec/compose-go/types"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/config/configfile"
Expand All @@ -33,19 +31,22 @@ import (
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/pkg/errors"
"gopkg.in/yaml.v2"

"github.com/docker/compose/v2/pkg/api"
)

// NewComposeService create a local implementation of the compose.Service API
func NewComposeService(dockerCli command.Cli) api.Service {
return &composeService{
dockerCli: dockerCli,
dockerCli: dockerCli,
maxConcurrency: -1,
}
}

type composeService struct {
dockerCli command.Cli
dockerCli command.Cli
maxConcurrency int
}

func (s *composeService) apiClient() client.APIClient {
Expand All @@ -56,6 +57,10 @@ func (s *composeService) configFile() *configfile.ConfigFile {
return s.dockerCli.ConfigFile()
}

func (s *composeService) MaxConcurrency(i int) {
s.maxConcurrency = i
}

func (s *composeService) stdout() *streams.Out {
return s.dockerCli.Out()
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/compose/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func (s *composeService) pull(ctx context.Context, project *types.Project, opts

w := progress.ContextWriter(ctx)
eg, ctx := errgroup.WithContext(ctx)
eg.SetLimit(s.maxConcurrency)

var mustBuild []string

Expand Down Expand Up @@ -270,6 +271,7 @@ func (s *composeService) pullRequiredImages(ctx context.Context, project *types.
return progress.Run(ctx, func(ctx context.Context) error {
w := progress.ContextWriter(ctx)
eg, ctx := errgroup.WithContext(ctx)
eg.SetLimit(s.maxConcurrency)
pulledImages := make([]string, len(needPull))
for i, service := range needPull {
i, service := i, service
Expand Down
1 change: 1 addition & 0 deletions pkg/compose/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func (s *composeService) Push(ctx context.Context, project *types.Project, optio

func (s *composeService) push(ctx context.Context, project *types.Project, options api.PushOptions) error {
eg, ctx := errgroup.WithContext(ctx)
eg.SetLimit(s.maxConcurrency)

info, err := s.apiClient().Info(ctx)
if err != nil {
Expand Down
12 changes: 12 additions & 0 deletions pkg/mocks/mock_docker_compose_api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9bc188b

Please sign in to comment.