Use request timeout for git service rpc (#20689) (#20693)

This enables git.Command's Run to optionally use the given context directly so its deadline will be respected. Otherwise, it falls back to the previous behavior of using the supplied timeout or a default timeout value of 360 seconds.

repo's serviceRPC() calls now use the context's deadline (which is unset/unlimited) instead of the default 6-minute timeout. This means that large repo clones will no longer arbitrarily time out on the upload-pack step, and pushes can take longer than 6 minutes on the receive-pack step.

Fixes #20680
This commit is contained in:
parnic 2022-08-06 21:37:48 -05:00 committed by GitHub
parent 92d79b556b
commit a04fc567b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 13 deletions

View file

@ -95,14 +95,15 @@ func (c *Command) AddArguments(args ...string) *Command {
return c return c
} }
// RunOpts represents parameters to run the command // RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored.
type RunOpts struct { type RunOpts struct {
Env []string Env []string
Timeout time.Duration Timeout time.Duration
Dir string UseContextTimeout bool
Stdout, Stderr io.Writer Dir string
Stdin io.Reader Stdout, Stderr io.Writer
PipelineFunc func(context.Context, context.CancelFunc) error Stdin io.Reader
PipelineFunc func(context.Context, context.CancelFunc) error
} }
func commonBaseEnvs() []string { func commonBaseEnvs() []string {
@ -171,7 +172,15 @@ func (c *Command) Run(opts *RunOpts) error {
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), opts.Dir) desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), opts.Dir)
} }
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc) var ctx context.Context
var cancel context.CancelFunc
var finished context.CancelFunc
if opts.UseContextTimeout {
ctx, cancel, finished = process.GetManager().AddContext(c.parentContext, desc)
} else {
ctx, cancel, finished = process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
}
defer finished() defer finished()
cmd := exec.CommandContext(ctx, c.name, c.args...) cmd := exec.CommandContext(ctx, c.name, c.args...)

View file

@ -474,11 +474,12 @@ func serviceRPC(ctx gocontext.Context, h serviceHandler, service string) {
cmd := git.NewCommand(h.r.Context(), service, "--stateless-rpc", h.dir) cmd := git.NewCommand(h.r.Context(), service, "--stateless-rpc", h.dir)
cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir)) cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir))
if err := cmd.Run(&git.RunOpts{ if err := cmd.Run(&git.RunOpts{
Dir: h.dir, Dir: h.dir,
Env: append(os.Environ(), h.environ...), Env: append(os.Environ(), h.environ...),
Stdout: h.w, Stdout: h.w,
Stdin: reqBody, Stdin: reqBody,
Stderr: &stderr, Stderr: &stderr,
UseContextTimeout: true,
}); err != nil { }); err != nil {
if err.Error() != "signal: killed" { if err.Error() != "signal: killed" {
log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String()) log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String())