api: ScaleOptions carries the replica counts it always pretended to · docker/compose@3ee4b5c · GitHub
Skip to content

Commit 3ee4b5c

Browse files
ndeloofglours
authored andcommitted
api: ScaleOptions carries the replica counts it always pretended to
The Compose interface promised 'Scale manages numbers of container instances running per service', but ScaleOptions had no replica count: callers had to know they must mutate project.Services[x] via SetScale before calling, and ScaleOptions.Services only tuned the recreation policy. An SDK consumer following the interface doc got a no-op convergence of the whole project. ScaleOptions gains Replicas (service -> count); the backend applies it to the model itself before converging, and derives the targeted services from its keys when Services is not set. The CLI now does what a CLI should: parse SERVICE=REPLICAS tuples and hand them to the backend, instead of pre-mutating the model. Passing a pre-mutated project with an empty Replicas map still behaves as before, so existing SDK callers are unaffected. Part of #14074 (B: pkg/api promises things the implementation does not honor). Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
1 parent 9a70c81 commit 3ee4b5c

4 files changed

Lines changed: 78 additions & 10 deletions

File tree

‎cmd/compose/scale.go‎

Lines changed: 1 addition & 7 deletions

‎pkg/api/api.go‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ type Compose interface {
137137
Viz(ctx context.Context, project *types.Project, options VizOptions) (string, error)
138138
// Wait blocks until at least one of the services' container exits
139139
Wait(ctx context.Context, projectName string, options WaitOptions) (int64, error)
140-
// Scale manages numbers of container instances running per service
140+
// Scale sets the number of replicas of the selected services
141+
// (ScaleOptions.Replicas) and converges the project to it, creating,
142+
// removing and starting containers as needed
141143
Scale(ctx context.Context, project *types.Project, options ScaleOptions) error
142144
// Export a service container's filesystem as a tar archive
143145
Export(ctx context.Context, projectName string, options ExportOptions) error
@@ -158,6 +160,13 @@ type VolumesOptions struct {
158160
type VolumesSummary = volume.Volume
159161

160162
type ScaleOptions struct {
163+
// Replicas maps a service name to the number of replicas it must run.
164+
// Scale applies these counts to the project model before converging it.
165+
Replicas map[string]int
166+
// Services selects the services whose containers may be recreated on
167+
// configuration divergence while converging (see CreateOptions.Services);
168+
// it does not scale anything by itself. When empty, it defaults to the
169+
// keys of Replicas.
161170
Services []string
162171
}
163172

‎pkg/compose/scale.go‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ package compose
1717

1818
import (
1919
"context"
20+
"maps"
21+
"slices"
2022

2123
"github.com/compose-spec/compose-go/v2/types"
2224

@@ -26,10 +28,31 @@ import (
2628

2729
func (s *composeService) Scale(ctx context.Context, project *types.Project, options api.ScaleOptions) error {
2830
return Run(ctx, tracing.SpanWrapFunc("project/scale", tracing.ProjectOptions(ctx, project), func(ctx context.Context) error {
29-
err := s.create(ctx, project, api.CreateOptions{Services: options.Services})
31+
if err := applyReplicas(project, options.Replicas); err != nil {
32+
return err
33+
}
34+
services := options.Services
35+
if len(services) == 0 {
36+
services = slices.Collect(maps.Keys(options.Replicas))
37+
}
38+
err := s.create(ctx, project, api.CreateOptions{Services: services})
3039
if err != nil {
3140
return err
3241
}
33-
return s.start(ctx, project.Name, api.StartOptions{Project: project, Services: options.Services}, nil)
42+
return s.start(ctx, project.Name, api.StartOptions{Project: project, Services: services}, nil)
3443
}), "scale", s.events)
3544
}
45+
46+
// applyReplicas applies the requested replica counts to the project model,
47+
// which is what the convergence performed by create/start acts upon.
48+
func applyReplicas(project *types.Project, replicas map[string]int) error {
49+
for name, scale := range replicas {
50+
service, err := project.GetService(name)
51+
if err != nil {
52+
return err
53+
}
54+
service.SetScale(scale)
55+
project.Services[name] = service
56+
}
57+
return nil
58+
}

‎pkg/compose/scale_test.go‎

Lines changed: 42 additions & 0 deletions

0 commit comments

Comments
 (0)