-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Pass and respect a Context
when initializing VUs
#2800
Conversation
Codecov Report
@@ Coverage Diff @@
## master #2800 +/- ##
==========================================
- Coverage 76.04% 75.85% -0.19%
==========================================
Files 213 211 -2
Lines 16554 16577 +23
==========================================
- Hits 12588 12575 -13
- Misses 3195 3223 +28
- Partials 771 779 +8
Flags with carried forward coverage won't be shown. Click here to find out more.
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
cea7276
to
a8ff4a1
Compare
8398f3f
to
11564b3
Compare
11564b3
to
3c041d2
Compare
3c041d2
to
ff2a8e4
Compare
ff2a8e4
to
dbde3c5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM from a first look, will make another pass later.
Nice job splitting it into atomic commits, makes reviewing much easier 👍
As for additional tests, and maybe I'm missing it, but I think there should be a test replicating the user pressing ^C
during VU initialization. I see a couple of tests sending os.Interrupt
, but it happens while the test is running. The tests aborted in init should cover the same code paths, but receiving SIGINT
should trigger it as well.
dbde3c5
to
ed39495
Compare
@imiric, I was super surprised that a test didn't exist, and when I started to add it, I realized why I hadn't done it originally 😅 This PR makes it so VU initializations are going to be gracefully aborted with Ctrl+C, true. However, k6 won't return the right exit code or send the Still, I decided to go ahead and add a test anyway, even if it needs to check the current values of these... I just added a couple of So, I cherry-picked one commit (d5124d1) from #2807, to simplify the integration tests that use Ctrl+C or REST API to stop k6, and then added ed39495 with the actual test to check what happens when an interrupt signal is given while VUs are initializing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing it, I saw very nice improvements. 🙇 I was reviewing when you force-pushed so something could be lost on my side.
// TODO: make something cleaner for interrupting scripts, and more unified | ||
// (e.g. as a part of the event loop or RunWithPanicCatching()? | ||
initCtxDone := init.moduleVUImpl.ctx.Done() | ||
initDone := make(chan struct{}) | ||
watchDone := make(chan struct{}) | ||
go func() { | ||
select { | ||
case <-initCtxDone: | ||
rt.Interrupt(init.moduleVUImpl.ctx.Err()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to check what the logic is in the other cases (not init) but if it is the same maybe could we delegate this listener directly in moduleVUImpl? 🤔
If the logic is different, we should use this opportunity to wrap the error so we know it is generated by the init process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately it wasn't straightforward to unify this init interrupt logic with the rest of the test abort logic during test execution 😞 At least I didn't see how to do that without a much, much bigger refactoring of the whole js/
package... 😞
So I chose to make only minor improvements in this PR (see the Simplify the js/Bundle.instantiate() API
commit) and leave the rest for a future PR (see the TODO in the code snippet you've selected).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the logic is different, we should use this opportunity to wrap the error so we know it is generated by the init process.
What about this, is it doable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm not sure what additional information we can add here, as the rest of the code is now 🤔 I think it will be much easier to fix this after we have the NewTestRunContext()
in a "higher" place, i.e. after #2813 🤔
47bd057
to
f0962a9
Compare
// TODO: make something cleaner for interrupting scripts, and more unified | ||
// (e.g. as a part of the event loop or RunWithPanicCatching()? | ||
initCtxDone := init.moduleVUImpl.ctx.Done() | ||
initDone := make(chan struct{}) | ||
watchDone := make(chan struct{}) | ||
go func() { | ||
select { | ||
case <-initCtxDone: | ||
rt.Interrupt(init.moduleVUImpl.ctx.Err()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the logic is different, we should use this opportunity to wrap the error so we know it is generated by the init process.
What about this, is it doable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
Just left a minor comment about test helpers.
}) | ||
} | ||
|
||
func asyncWaitForStdoutAndStopTestFromRESTAPI( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is only called from TestAbortedByUserWithRestAPI
, and just wraps another helper function. So I would inline the asyncWaitForStdoutAndRun()
call, and remove this.
asyncWaitForStdoutAndRun()
is also called with the same arguments, except for the callback func. So I would drop the unneded arguments, and add them once they're needed.
In general, abstractions add a layer of indirection that complicates code comprehension, so I wouldn't use them so liberally, and would prefer even some duplication between tests. Or, if tests really are similar, turn them into table tests and avoid the helper functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree and I was about to fix this, but I think the "fix" here is to just add more tests that abort the test run via the k6 REST API 😅 See #2804, we need more tests about this behavior... 😞
In #2815 or soon after it, we should be able to nicely abort the test with the REST even during VU init or setup()
, so I'd prefer to keep this helper method here and add more tests that use it in that PR.
With some extra work, this will allow us to gracefully interrupt VUs in the middle of their initialization.
As I've mentioned in the code comments, this test doesn't test the eventually desired behavior, it tests the currently expected behavior as it is. The current behavior is still much better than the behavior before this PR, where the VU init was interrupted without any handling and graceful stops. However, the fix to actually abort k6 with the correct exit code and run_status will be in another PR.
f0962a9
to
9c9e35f
Compare
9c9e35f
to
a7ad53f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This closes #2790. It is not very urgent, it doesn't need to be released in v0.42.0, instead it is meant to be merged some time early in the v0.43.0 cycle.
Most of the LoC changes are just boilerplate churn, mostly test and API signature adjustments. They have been grouped together into the first 2 commits of the PR and should contain no functional or test changes.
The important changes are focused in the next 2 commits, which should be the reviewed carefully. I may add some more tests there, though I am not sure what they should be 🤔 If anyone has any ideas, please share 🙏