Repository navigation
[shell-operator] Let an embedding application choose how hooks are run - #942
Merged
Merged
Conversation
Every event runs a hook by starting it as a child process. For an interpreted hook most of that time is interpreter start-up and imports: in deckhouse webhook-handler a Python validating hook takes 24-32 ms, of which about 2 ms is the hook itself. executor.Runner lets the application that links shell-operator decide how a prepared hook command is run, for example by handing it to a long-lived interpreter that forks per event. It is set with WithHookRunner on the ShellOperator, or HookRunner in hook.ManagerConfig. Nothing changes by default: ProcessRunner keeps starting a process, and the --config call made while loading hooks always starts one. Log proxying, StderrError and resource usage reporting stay in the executor and apply to any Runner. Signed-off-by: Yuriy Losev <yuriy.losev@flant.com>
fuldaxxx
approved these changes
Oct 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Adds
executor.Runner: the application that links shell-operator as a library can decide how a hook is run for an event. The default stays the same, every hook is started as a child process.What this PR does / why we need it
Every event starts the hook as a new process. For a Python hook most of that time goes to interpreter start-up and imports. In deckhouse webhook-handler, which runs admission and conversion webhooks through shell-operator, one Python validating hook takes 24-32 ms, and about 2 ms of it is the hook itself (python:3.12-alpine, 1 CPU). A long-lived interpreter that forks per event runs the same hook in 1.9 ms.
This PR adds the extension point for that, without changing anything by default:
executor.Runnerwith one method,Run(ctx, *exec.Cmd) (*CmdUsage, error). The command carries the hook path, arguments, environment, working directory and the stdout/stderr writers.executor.ProcessRunneris the existing behaviour moved behind the interface: start, register the PID for the zombie reaper, wait, report rusage.shell_operator.WithHookRunner(...), orHookRunnerinhook.ManagerConfig, and reaches every hook throughHookManager.StderrErrorand the error returned to the caller stay inExecutor.RunAndLogLinesand apply to any runner.--configcall made while loading hooks always starts a process.Special notes for your reviewer
TestRunAndLogLines_WithRunnercovers output and errors through a custom runner and the nil fallback.Test_ManagerConfig_HookRunner_RunsHookschecks that the runner fromManagerConfigreachesHook.Runand that--configis still fetched by starting a process. The second test fails when the line that wires the runner into hooks is removed.go test ./pkg/...passes.