feat(job-array-one-based-index): clamp the apiserver array size limit (task 5.2)

job.max_array_size is resolved by a pure resolveMaxArraySize: unset or 0
gives 1000, 1..32767 is used as is, values above 32767 are clamped to
32767 with a startup warning naming the configured and effective value,
and a negative value refuses startup. The old >2147483646 rejection is
gone; the shipped config documents the bounds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-10-01 11:32:25 +00:00
parent b88e352616
commit 7f417262c5
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
4 changed files with 189 additions and 24 deletions

View file

@ -10,13 +10,14 @@ import (
"strings"
"github.com/spf13/viper"
"go.uber.org/zap"
)
type BackendConfig struct {
Address string `yaml:"address"`
Port int `yaml:"port"`
From string `yaml:"from"`
Key string `yaml:"key"`
Address string `yaml:"address"`
Port int `yaml:"port"`
From string `yaml:"from"`
Key string `yaml:"key"`
// Peers lists additional controller candidates for HA mode in "host:port"
// format. When non-empty, RegisterToBackend tries each candidate in order
// and connects to whichever accepts the join as primary. Address+Port
@ -206,24 +207,19 @@ func InitConf() error {
DisallowedTypes: viper.GetStringSlice("file_upload.disallowed_types"),
}
// parse job config section
// parse job config section
if !viper.IsSet("job") {
// if job section is not set, use default values
JobYamlConfig = &JobConfig{
MaxArraySize: 1000,
}
} else {
maxArraySize := viper.GetInt("job.max_array_size")
if maxArraySize == 0 {
maxArraySize = 1000
}
if maxArraySize < 1 || maxArraySize > 2147483646 {
return fmt.Errorf("invalid job.max_array_size value: %d, must be between 1 and 2147483646", maxArraySize)
}
JobYamlConfig = &JobConfig{
MaxArraySize: maxArraySize,
}
// parse job config section; an absent section or key reads as 0 (default)
configuredArraySize := viper.GetInt("job.max_array_size")
maxArraySize, clamped, err := resolveMaxArraySize(configuredArraySize)
if err != nil {
return err
}
if clamped {
Warn("job.max_array_size above supported maximum",
zap.Int("configured", configuredArraySize),
zap.Int("effective", maxArraySize))
}
JobYamlConfig = &JobConfig{
MaxArraySize: maxArraySize,
}
// parse cache config section
@ -289,6 +285,31 @@ func ParseMaxSize(maxSize string) (int64, error) {
return size, nil
}
const (
// defaultMaxArraySize is used when job.max_array_size is unset or 0.
defaultMaxArraySize = 1000
// supportedMaxArraySize is the largest array the API server creates
// (array element numbers are 1..32767).
supportedMaxArraySize = 32767
)
// resolveMaxArraySize turns the configured job.max_array_size into the
// effective array size limit: 0 (unset) gives the default 1000, 1..32767 is
// used as is, anything above 32767 is clamped to 32767 (clamped = true, the
// caller logs a warning), and a negative value is an error.
func resolveMaxArraySize(v int) (effective int, clamped bool, err error) {
switch {
case v < 0:
return 0, false, fmt.Errorf("invalid job.max_array_size value: %d, must not be negative", v)
case v == 0:
return defaultMaxArraySize, false, nil
case v > supportedMaxArraySize:
return supportedMaxArraySize, true, nil
default:
return v, false, nil
}
}
// resolveJWTSecret returns the JWT secret from XCE_JWT_SECRET env var if set and non-empty,
// otherwise falls back to the value from config file.
func resolveJWTSecret(configValue string) string {