-
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
Hooks for extensions - e.g. graceful shutdown, per VU/iteration, etc. #2432
Comments
I feel like maybe some kind of full blown event system that possibly is also available to js scripts will be better solution. Some links:
|
I'm going to describe the problem that we're having in the context of
The suggestions outlined in the description of this issue are good. Just some points that I think should be covered or considered in this work:
|
For your particular case I would expect that you can workaround, as long as you don't need anything to be executed on the event loop - js code usually:
Something a kin to func (b *Browser) connect() {
// other code
callback := b.vu.RegisterCallack()
go func() {
defer.callback()
<-b.vu.Context(), <-b.stop:
// all cleanup here
}()
// rest of connect code
} Otherwise - yes a lot of those are likely going to be required which is why the issue is a lot more involved than it might seem at first glance. |
Thanks for this, we will give this work around a go if we have time in the next cycle. |
The browser module is making changes to abstract away the chromium browser lifecycle away from the user. This will allow the browser module to better utilise the test generator resources so that a suitable number of chromium instances can be launched before the test is started, and those same instances are used throughout the test run instead of launching and closing many chrome instances per iteration. This abstraction will affect the browser module APIs, which are being explored in https://github.com/grafana/k6-cloud/issues/1077. While working through the API changes, we realised that there is one issue that we keep hitting upon, which is that the browser module is unable to close the chromium subprocess as it's missing a signal from k6. Here are two solutions worth mentioning and the problems associated to each of them:
When the vu ends unsuccessfully, the browser module can rely on the workaround that is described in this comment. When the vu ends successfully the browser module cannot rely on this workaround as it seems to hang indefinitely waiting on the context to close. When an iteration ends, the browser module can rely on the context in the vu to close, which is a useful signal that it will likely use to cleanup the test iteration that has ended. What the browser module now needs is a signal from k6 when it is shutting down regardless of whether the whole test run was successful or not. |
Something else that would help the browser module is a "start of test run" (similar to the This would help us to create all the chrome/firefox/etc instances, Currently, if we wanted to do the same, we'd need to do it during the test runtime i.e. when a browser module method is called. Fo example in the following test we're having to do all this up front creation of the pool when import { browser } from 'k6/x/browser'
import { sleep } from 'k6'
export default async function () {
const page = browser.newPage() // At the moment we're doing all this up front creation here
try {
await page.goto('https://test.k6.io/')
sleep(1);
} finally {
page.close()
context.close()
}
} It's a stretch goal though, as we think that the challenge might be getting the initialised |
After discussing this with Ankur over Slack, the browser module essentially needs a setup/teardown hook at the module level. Hooking into the script's A quick hack that doesn't involve a full event system could be to add an interface that wraps Let's discuss this at today's sync meeting and align on the way forward. |
Feature Description
Currently k6 extensions are abruptly terminated in some scenarios, e.g. when pressing
^C
, as we've found out in grafana/xk6-browser#268 (comment). This doesn't leave any time for extensions to cleanup and do a clean shutdown, which in xk6-browser's case would involve closing the browser connection, though in general k6 should ensure that any pending event loop operations are processed as well. For example, it would be good DX to allow the Promise rejection handlers to run, but this is up for debate whether^C
should interrupt those as well.Suggested Solution
One or more of these might be a good idea:
Passing a cancelable context to extensions via the
moduleVUImpl
here. This context could then be cancelled first whenever k6 starts shutting down (whether that's abruptly with^C
or otherwise).Allow extensions to specify a callback for "deregistration"/cleanup, either via the
modules.Register()
method, or anothermoduleVUImpl
method. k6 would then run this first before shutdown. A drawback with this might be that callbacks might run an arbitrary amount of time, but we can always timeout on it.Maybe alternatively to the point above, pass a "shutdown" channel to extensions that extensions can use to signal that they're done with cleanup. This might be more flexible and simpler to timeout on.
If we do decide to have a timeout, it should probably use a sane default value but be user configurable.
Already existing or connected issues / PRs
Browser.on(event)
xk6-browser#268The text was updated successfully, but these errors were encountered: