-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Integrate Binary provisioning #4671
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
Conversation
c1d3f2d
to
42392ac
Compare
Decision mechanics if custom k6 build required
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
b521a97
to
4c111b7
Compare
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
internal/cmd/launcher.go
Outdated
return // this is required for testing | ||
} | ||
|
||
// if the command does not have dependencies or a custom build |
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 command does not have dependencies or a custom build | |
// if the command does not have dependencies nor a custom build is required |
cmd.Stdin = os.Stdin | ||
|
||
// Copy environment variables to the k6 process and skip binary provisioning feature flag to disable it. | ||
// If not disabled, then the executed k6 binary would enter an infinite loop, where it continuously |
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.
Can we add a // TODO
here, please? I guess this shouldn't be a problem anymore in the future. Right?
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 think it will always be required/desirable to signal the subprocess that the binary provisioning is not required to avoid the overhead of reanalyzing the dependencies.
internal/cmd/launcher.go
Outdated
// process the input script, detect dependencies, and retrigger provisioning. | ||
env := []string{} | ||
for k, v := range gs.Env { | ||
if k == "K6_BINARY_PROVISIONING" { |
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'd say I have seen this literal string at least a couple of times along this PR, so I'd prefer if we can move this into a const
, so prevent mistakes in the future, in case it changes, possible typos, etc.
internal/cmd/launcher.go
Outdated
} | ||
|
||
// isScriptRequired searches for the command and returns a boolean indicating if it is required to pass a script or not | ||
func isScriptRequired(args []string) bool { |
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.
In case we run k6 cloud run
with --local-execution
, I think this should return false
, as I guess it's equivalent to k6 run
, isn't it? 🤔
Or, do we intentionally want to run a custom binary locally in such case?
In any case, I'd suggest to add that case to TestIsScriptRequired
, so we leave it explicit. Perhaps even accompanied with a code comment, as in my opinion isn't obvious.
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.
could run --local-execution
is expected to run with binary provisioning. We are not making a difference with cloud run
.
if strings.HasSuffix(arg, ".js") || | ||
strings.HasSuffix(arg, ".tar") || | ||
strings.HasSuffix(arg, ".ts") { | ||
return arg | ||
} |
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 still think this isn't a good idea because:
- k6 normally works despite of the file extension.
- If I have binary provisioning enabled, it breaks the execution flow even when there's no dependency to analyze.
- The error is confusing, because it says:
error="script not found"
, while arguably the problem is that the file extension isn't supported/recognized as a file script, or something along those lines.
In my opinion, we should try to fix at least 2 and 3 before merging PR. 1 is something we can work later, I guess - I'd appreciate if we can create and issue for that, so we don't forget about remaining work, please.
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.
My understanding is that we accepted this as a limitation for the preview and document it as a known issue..
Addressing this issue in the current logic is complex and probably will still fail in some cases.
It is documented here: #4727
@joanlopez Regarding the issue you mention with cancelling a cloud execution in the subprocess, the fact you see this message
Means that the subprocess is actually being properly stopped by the parent. Otherwise, you woulnd' t see that message. My guess is that you still see the process because as this message says, it is waiting for the cloud.:
I'm not sure what the expectation is in this case. Should the parent wait for the children? to finish. I'm not 100% sure, but I would expect this to be the case. So I'm not sure why the parent finishes first cc @codebien |
Same here, that's why I asked. |
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
It should be related to the signal trap enabled by the subprocess where the launcher doesn't have any because it doesn't reach that part of the code. |
@codebien commented that the cause is we are not handling the signal in the parent, so it is ending prematurely. |
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.
LGMT (with my current level of context on the topic) 👍🏻 🚀
Once the signals handling PR is merged, I think this is good to go. I share some of the observations already made, but considering we already have most of the points raised on the radar documented as issues to be tackled in further iterations 👍🏻 on my end.
Really happy to see this (tentatively) passing the finish line 🏁 Grateful for the work you put in @pablochacin 👏🏻
|
||
// provision generates a custom binary from the received list of dependencies | ||
// with their constrains, and it returns an executor that satisfies them. | ||
provision func(*state.GlobalState, k6deps.Dependencies) (commandExecutor, error) |
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.
Nit (feel free to ignore/dismiss): although it is not strictly necessary here, I tend to prefer, when possible, defining and implementing an interface (Provisioner
?), instead of a callback. The reason is ease of debugging and codebase navigation in IDEs. It's much easier to go to definition of an interface and ask for implementations, than to track down where the concrete callback instance is defined and passed down. Sometimes it also makes testing more straightforward.
No arguing on my end, really just a suggestion and expressing a preference, I'm okay with it as-is 👍
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.
@pablochacin I agree with @oleiade, at least it should be worth to have a reflection/attempt on refactoring it. Can you open and add an issue to the stability epic, please?
@pablochacin additional reason for #4737 Help for subcommands seems an additional issue with the current solution: K6_BINARY_PROVISIONING=1 k6 cloud run --help
ERRO[0000] Binary provisioning is enabled but it failed to analyze the dependencies. Please, make sure to report this issue by opening a bug report. error="script not found" |
* handle signals Signed-off-by: Pablo Chacin <pablochacin@gmail.com> * attend review comments Signed-off-by: Pablo Chacin <pablochacin@gmail.com> --------- Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
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 👍 Nice work.
Migrate from k6provider to k6 dir for builds' cache --------- Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
Signed-off-by: Pablo Chacin <pablochacin@gmail.com>
What?
Integrate into k6 the logic for dynamically provision a k6 custom binary that includes the dependencies (extensions) required by a test.
This change set introduces the launcher as the new starting point for executing k6. The launcher checks if a binary provisioning is enabled and if it is required to execute the command. If not, it delegates the executing to the regular execution entry point.
Binary provisioning is required if the command processes a script or archive (
run
,archive
, ...) and the input has a dependency that cannot be resolved with the current k6 binary. This is resolved by thek6deps
library that scans the input for imports of k6 extensions.If a new binary is required, it is downloaded from the build service using the
k6provider
library. This requires a cloud token for authentication. Binaries are stored in a local cache, so subsequent requests will be served from the local file system instead of downloading it.Note: This is a work in progress. It is fully functional, but a few tasks are still pending:
TODO:
Also, some features are intended for follow-up PRs:
FOLLOW-UP:
Why?
We'd like k6 to be able to run scripts with extensions without recompiling the binary
Checklist
make check
) and all pass.Checklist: Documentation (only for k6 maintainers and if relevant)
Please do not merge this PR until the following items are filled out.
Related PR(s)/Issue(s)