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

How to login VU in the init code? #784

Closed
kkeranen opened this issue Sep 28, 2018 · 2 comments
Closed

How to login VU in the init code? #784

kkeranen opened this issue Sep 28, 2018 · 2 comments

Comments

@kkeranen
Copy link

I want to login each VU before running the actual performance test. I can't do it in setup function because it's no VU specific. Yet moving the code outside the default function causes compilation error (see the end of the message).

Original working code:

export default () => {
  // Initialization: login
  let idToken = getIdToken();
  let selfToken = authenticate(idToken);   
  
  // performance test
  ping(selfToken); 
};

The code doesn't compile if I move the two lines of login code outside the function as init code. The problem is that login is more complex operation (several http method calls) than a simple API call ("ping" in this case, only single http get), so including login to default function would test mostly the performance of login. Any advice on this problem?

Error below:

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: Panic at 28: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: Panic at 28: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x120 pc=0xac1dec]

goroutine 1 [running]:
github.com/loadimpact/k6/vendor/github.com/dop251/goja.(*Runtime).RunProgram.func1(0xc044baa5e8)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/runtime.go:880 +0xa0
panic(0xbfa300, 0xc042bc4530)
C:/Go/src/runtime/panic.go:502 +0x237
github.com/loadimpact/k6/vendor/github.com/dop251/goja.(*vm).try.func1(0xc04207b110, 0x0, 0xc044baa4e0, 0x0, 0x0, 0x0, 0xc044baa538)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/vm.go:364 +0x463
panic(0xc117c0, 0x14d6280)
C:/Go/src/runtime/panic.go:502 +0x237
github.com/loadimpact/k6/js/modules/k6/http.(*HTTP).parseRequest(0xc04216f200, 0xe9ef60, 0xc04337d950, 0xd1fe78, 0x4, 0xc043391400, 0xc0438b893e, 0x51, 0xc0438b893e, 0x51, ...)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/js/modules/k6/http/http_request.go:142 +0x21c
github.com/loadimpact/k6/js/modules/k6/http.(*HTTP).Request(0xc04216f200, 0xe9ef60, 0xc04337d950, 0xd1fe78, 0x4, 0xea5cc0, 0xc042863970, 0xc043140d40, 0x2, 0x2, ...)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/js/modules/k6/http/http_request.go:108 +0x1a4
github.com/loadimpact/k6/js/modules/k6/http.(*HTTP).Post(0xc04216f200, 0xe9ef60, 0xc04337d950, 0xea5cc0, 0xc042863970, 0xc043140d40, 0x2, 0x2, 0x0, 0x0, ...)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/js/modules/k6/http/http_request.go:73 +0xa6
reflect.Value.call(0xccd640, 0xc04216f200, 0x2213, 0xd24ee6, 0x9, 0xc0423b7400, 0x3, 0x3, 0xc94da0, 0xc042bc4390, ...)
C:/Go/src/reflect/value.go:447 +0x970
reflect.Value.CallSlice(0xccd640, 0xc04216f200, 0x2213, 0xc0423b7400, 0x3, 0x3, 0x194, 0xc0423d6e70, 0xc044baa300)
C:/Go/src/reflect/value.go:321 +0xab
github.com/loadimpact/k6/js/common.Bind.func1(0xea5ae0, 0xc0431405a0, 0xc0439b7670, 0x3, 0x19, 0x1de13f8, 0x0)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/js/common/bridge.go:210 +0x89d
github.com/loadimpact/k6/vendor/github.com/dop251/goja.(*vm)._nativeCall(0xc04207b110, 0xc0423d6e70, 0x3)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/vm.go:1826 +0x2b5
github.com/loadimpact/k6/vendor/github.com/dop251/goja.call.exec(0x3, 0xc04207b110)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/vm.go:1810 +0x524
github.com/loadimpact/k6/vendor/github.com/dop251/goja.(*vm).run(0xc04207b110)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/vm.go:288 +0x58
github.com/loadimpact/k6/vendor/github.com/dop251/goja.(*vm).(github.com/loadimpact/k6/vendor/github.com/dop251/goja.run)-fm()
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/vm.go:375 +0x31
github.com/loadimpact/k6/vendor/github.com/dop251/goja.(*vm).try(0xc04207b110, 0xc044baa540, 0x0)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/vm.go:370 +0x113
github.com/loadimpact/k6/vendor/github.com/dop251/goja.(*vm).runTry(0xc04207b110, 0xe2c268)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/vm.go:375 +0x4d
github.com/loadimpact/k6/vendor/github.com/dop251/goja.(*Runtime).RunProgram(0xc042a4b980, 0xc042134ea0, 0x0, 0x0, 0x0, 0x0)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/dop251/goja/runtime.go:891 +0x1c9
github.com/loadimpact/k6/js.(*Bundle).instantiate(0xc043682400, 0xc042a4b980, 0xc042fc7950, 0x30, 0x3a)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/js/bundle.go:261 +0x479
github.com/loadimpact/k6/js.NewBundle(0xc0422ceb70, 0xea4b20, 0x15089d0, 0xc042080001, 0xc0422cebd0, 0x0, 0x0, 0xe)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/js/bundle.go:86 +0x3f7
github.com/loadimpact/k6/js.New(0xc0422ceb70, 0xea4b20, 0x15089d0, 0x1, 0xc0422cebd0, 0xc04208ea48, 0x74e275, 0xc04232c480)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/js/runner.go:65 +0x66
github.com/loadimpact/k6/cmd.newRunner(0xc0422ceb70, 0xd1f659, 0x2, 0xea4b20, 0x15089d0, 0x1, 0xc0422cebd0, 0x10000000000003a, 0xc0422ceb70, 0x0, ...)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/cmd/run.go:466 +0x3a0
github.com/loadimpact/k6/cmd.newRunner(0xc0422ceb70, 0x0, 0x0, 0xea4b20, 0x15089d0, 0x1500001, 0xc0422cebd0, 0xc042004010, 0xc0422ceb70, 0x0, ...)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/cmd/run.go:464 +0x47d
github.com/loadimpact/k6/cmd.glob..func11(0x14e0c60, 0xc0422d8760, 0x1, 0x2, 0x0, 0x0)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/cmd/run.go:119 +0x461
github.com/loadimpact/k6/vendor/github.com/spf13/cobra.(*Command).execute(0x14e0c60, 0xc0422d8720, 0x2, 0x2, 0x14e0c60, 0xc0422d8720)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/spf13/cobra/command.go:698 +0x474
github.com/loadimpact/k6/vendor/github.com/spf13/cobra.(*Command).ExecuteC(0x14e0a40, 0x52, 0xc0422d81a0, 0xc0422fe000)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/spf13/cobra/command.go:783 +0x2eb
github.com/loadimpact/k6/vendor/github.com/spf13/cobra.(*Command).Execute(0x14e0a40, 0xc042093f78, 0x403b83)
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/vendor/github.com/spf13/cobra/command.go:736 +0x32
github.com/loadimpact/k6/cmd.Execute()
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/cmd/root.go:87 +0x38
main.main()
C:/Users/Luiz Filho/go/src/github.com/loadimpact/k6/main.go:28 +0x27

@na--
Copy link
Member

na-- commented Sep 28, 2018

The described bug is a duplicate of this one #699

However, my initial instinct was to fix that bug by just disabling http support in the init code, not by implementing it. Thinking about it again, after reading your post, I'm starting to reconsider...

You can currently implement per-VU initialization in the default function by using the __ITER execution context variable like this:

export default function () {
    if (__ITER == 0) {
        initVU();
    }
    normalVUCode();
}

You can also use global variables in each VU (example) to save some state that you initialize in the first iteration of each VU as determined by that __ITER variable. The issue with such an approach though is that it would skew the iteration_duration of that first iteration...

You can also use setup() to initialize things for all VUs, return the credentials in an array and then use the __VU execution context variable so each VU uses its own credentials. That's a bit awkward, but it won't skew the iteration_duration metric.

@na--
Copy link
Member

na-- commented Sep 28, 2018

After some more consideration and an internal discussion, I realized that there's a very good reason behind my initial instinct of not allowing HTTP requests and other similar code directly in the init phase.

The init phase is actually executed a few more times beyond the once-per-VU we mention in the docs. We implicitly execute it when we initialize the JS runtimes to run the setup() and teardown() functions in, but most importantly - we run it once in the beginning of the script so we can get the exported options from it (among other things). That happens both when running the script locally with k6 run, but also when creating a script archive bundle - both explicitly via the k6 archive command and implicitly when we bundle the script for distributed execution by running k6 cloud.

So for now you'd have to use one of the two workarounds I mentioned in the previous message. But your use case is very valid and probably quite common one, so ideally we should have a better solution for it at some point. @robingustafsson suggested that we can add a new lifecycle function called init(setupData)/initVU(setupData)/setupVU(setupData) or something like that. It will be called once in each VU, after the global setup() is done (thus it will receive the setupData that setup() returned), but before the actual load test (looping execution of the default function) starts. It will be executed in the actual VU runtimes, so it can save any state as global variables in the VU for later access by the default function. And having it as a separate function won't skew the iteration_duration metric and won't take up some of the specified script duration time (another drawback of the workaround I proposed above). We can even tag any resulting metrics appropriately, like we do with the ones from setup() and teardown() now.

I'll close this issue as a duplicate of #699, but I'll also create a new one later that links to this and describes the use case and the proposed new initVU() lifecycle function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants