Check NOFILE limit before creating local storage engine

Signed-off-by: Alejandro Lopez <a.lopez@yadro.com>
This commit is contained in:
Alejandro Lopez 2023-04-21 14:01:30 +03:00
parent 5ab7cfed7c
commit 81b7d3f536

View file

@ -31,6 +31,7 @@ import (
"go.k6.io/k6/js/modules" "go.k6.io/k6/js/modules"
"go.k6.io/k6/metrics" "go.k6.io/k6/metrics"
"go.uber.org/zap" "go.uber.org/zap"
"golang.org/x/sys/unix"
) )
// RootModule is the global module object type. It is instantiated once per test // RootModule is the global module object type. It is instantiated once per test
@ -77,6 +78,28 @@ func NewLocalModuleInstance(vu modules.VU, resolveEngine func(context.Context, s
} }
} }
// checkResourceLimits checks the current limit on NOFILE.
//
// The usual default is around 1024 and this is too low for production clusters where a value of
// about 65536 is needed in order to not run into errors because of attempting to open too many files.
// This is needed for the local storage engine scenarios, where the user running the scenario is not
// necessarily the service user, for which the limits are preconfigured correctly.
//
// See: https://k6.io/docs/misc/fine-tuning-os/
func checkResourceLimits() error {
const (
minNofileLimit = 1 << 16
)
rlimit := &unix.Rlimit{}
if err := unix.Getrlimit(unix.RLIMIT_NOFILE, rlimit); err != nil {
return fmt.Errorf("getting resource limits: %v", err)
}
if rlimit.Cur < minNofileLimit {
return fmt.Errorf("nofile limit is too low: %d", rlimit.Cur)
}
return nil
}
// GetOrCreateEngine returns the current engine instance for the given configuration file, // GetOrCreateEngine returns the current engine instance for the given configuration file,
// creating a new one if none exists. Note that the identity of configuration files is their // creating a new one if none exists. Note that the identity of configuration files is their
// file name for the purposes of test runs. // file name for the purposes of test runs.
@ -96,6 +119,9 @@ func (r *RootModule) GetOrCreateEngine(ctx context.Context, configFile string, d
if err != nil { if err != nil {
return nil, fmt.Errorf("creating engine options from config: %v", err) return nil, fmt.Errorf("creating engine options from config: %v", err)
} }
if err := checkResourceLimits(); err != nil {
return nil, err
}
r.ng = engine.New(ngOpts...) r.ng = engine.New(ngOpts...)
for i, opts := range shardOpts { for i, opts := range shardOpts {
if _, err := r.ng.AddShard(opts...); err != nil { if _, err := r.ng.AddShard(opts...); err != nil {