Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new ConfigMap fields for service initial scale #7674

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions pkg/autoscaler/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ type Config struct {
// the number of activators per revision.
ActivatorCapacity float64

// AllowZeroInitialScale indicates whether InitialScale and
// autoscaling.internal.knative.dev/initialScale are allowed to be set to 0.
AllowZeroInitialScale bool

// InitialScale is the cluster-wide default initial revision size for newly deployed
// services. This can be set to 0 iff AllowZeroInitialScale is true.
InitialScale int32

// General autoscaler algorithm configuration.
MaxScaleUpRate float64
MaxScaleDownRate float64
Expand Down Expand Up @@ -99,6 +107,8 @@ func defaultConfig() *Config {
ScaleToZeroGracePeriod: 30 * time.Second,
TickInterval: 2 * time.Second,
PodAutoscalerClass: autoscaling.KPA,
AllowZeroInitialScale: false,
InitialScale: 1,
}
}

Expand All @@ -118,6 +128,9 @@ func NewConfigFromMap(data map[string]string) (*Config, error) {
{
key: "enable-graceful-scaledown",
field: &lc.EnableGracefulScaledown,
}, {
key: "allow-zero-initial-scale",
field: &lc.AllowZeroInitialScale,
}} {
if raw, ok := data[b.key]; ok {
*b.field = strings.EqualFold(raw, "true")
Expand Down Expand Up @@ -165,6 +178,25 @@ func NewConfigFromMap(data map[string]string) (*Config, error) {
}
}

// Process int fields
for _, i := range []struct {
key string
field *int32
defaultValue int32
}{{
key: "initial-scale",
field: &lc.InitialScale,
defaultValue: 1,
}} {
if raw, ok := data[i.key]; !ok {
*i.field = i.defaultValue
} else if val, err := strconv.ParseInt(raw, 10, 32); err != nil {
return nil, err
} else {
*i.field = int32(val)
}
}

taragu marked this conversation as resolved.
Show resolved Hide resolved
// Adjust % ⇒ fractions: for legacy reasons we allow values in the
// (0, 1] interval, so minimal percentage must be greater than 1.0.
// Internally we want to have fractions, since otherwise we'll have
Expand Down Expand Up @@ -248,6 +280,12 @@ func validate(lc *Config) (*Config, error) {
return nil, fmt.Errorf("panic-window-percentage = %v, must be in [%v, 100] interval", lc.PanicWindowPercentage, 100*float64(BucketSize)/float64(lc.StableWindow))
}

if lc.InitialScale < 0 {
return nil, fmt.Errorf("initial-scale = %v, must be at least 0 (or at least 1 when allow-zero-initial-scale is false)", lc.InitialScale)
}
if lc.InitialScale == 0 && !lc.AllowZeroInitialScale {
return nil, fmt.Errorf("initial-scale = %v, must be at least 1 since allow-zero-initial-scale is false", lc.InitialScale)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we re-arrange in the reverse order, then we can go back to the previous errors messages, since they'd be correct, I think. But probably isn't important much.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand. What do you mean by "we can go back to the previous errors messages"?

Copy link
Contributor

@vagababov vagababov Apr 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eh, basically

if x < 0 || x==0 && !allow {
  return "must be non-negative or positive if allow is unset"
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about:

minInitialScale := 1
if lc.AllowZeroInitialScale {
  minInitialScale = 0
}
if lc.InitialScale < minInitialScale {
  return nil, fmt.Errorf("initial-scale = %d, must be at least %d", lc.InitialScale, minInitialScale)
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well we kind of had that before :-)
It's bikeshedding at this point. I like mine, since it has single if :)

return lc, nil
}

Expand Down
43 changes: 43 additions & 0 deletions pkg/autoscaler/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,49 @@ func TestNewConfig(t *testing.T) {
"scale-to-zero-grace-period": "4s",
},
wantErr: true,
}, {
name: "with prohibited default initial scale",
input: map[string]string{
"allow-zero-initial-scale": "false",
"initial-scale": "0",
},
wantErr: true,
}, {
name: "with negative default initial scale",
input: map[string]string{
"allow-zero-initial-scale": "false",
"initial-scale": "-1",
},
wantErr: true,
}, {
name: "with non-parseable default initial scale",
input: map[string]string{
"allow-zero-initial-scale": "false",
"initial-scale": "invalid",
},
wantErr: true,
}, {
name: "with valid default initial scale",
input: map[string]string{
"allow-zero-initial-scale": "true",
"initial-scale": "0",
},
want: func() *Config {
c := defaultConfig()
c.AllowZeroInitialScale = true
c.InitialScale = 0
return c
}(),
}, {
name: "with non-parseable allow-zero-initial-scale",
input: map[string]string{
"allow-zero-initial-scale": "invalid",
},
want: func() *Config {
c := defaultConfig()
c.AllowZeroInitialScale = false
return c
}(),
taragu marked this conversation as resolved.
Show resolved Hide resolved
}}

for _, test := range tests {
Expand Down