1
0
Fork 0
mirror of https://code.forgejo.org/forgejo/runner.git synced 2025-10-15 19:42:06 +00:00

fix: enforce job.<job_id>.timeout-minutes

- enforce timeout-minutes timeout for jobs in a way similar
  to how it is done for steps
- minimal refactor of evaluateStepTimeout evaluateTimeout so it
  can be used by jobs as well, with additional debug information
  and error logging if parsing fails
- add integration tests for both step and job timeout-minutes,
  verifying expressions are allowed and evaluated

Resolves forgejo/runner#979
This commit is contained in:
Earl Warren 2025-09-11 08:48:16 +02:00
parent 3dd167d770
commit a100041dd4
No known key found for this signature in database
GPG key ID: 0579CB2928A78A00
6 changed files with 39 additions and 6 deletions

View file

@ -943,7 +943,10 @@ func (rc *RunContext) Executor() (common.Executor, error) {
return err
}
if res {
return executor(ctx)
timeoutctx, cancelTimeOut := evaluateTimeout(ctx, rc.ExprEval, rc.Run.Job().TimeoutMinutes)
defer cancelTimeOut()
return executor(timeoutctx)
}
return nil
}, nil

View file

@ -272,6 +272,8 @@ func TestRunner_RunEvent(t *testing.T) {
{workdir, "evalmatrix-merge-array", "push", "", platforms, secrets},
{workdir, "basic", "push", "", platforms, secrets},
{workdir, "timeout-minutes-stop", "push", "Job 'check' failed", platforms, secrets},
{workdir, "timeout-minutes-job", "push", "context deadline exceeded", platforms, secrets},
{workdir, "fail", "push", "Job 'build' failed", platforms, secrets},
{workdir, "runs-on", "push", "", platforms, secrets},
{workdir, "checkout", "push", "", platforms, secrets},

View file

@ -177,7 +177,7 @@ func runStepExecutor(step step, stage stepStage, executor common.Executor) commo
Mode: 0o666,
})(ctx)
timeoutctx, cancelTimeOut := evaluateStepTimeout(ctx, rc.ExprEval, stepModel)
timeoutctx, cancelTimeOut := evaluateTimeout(ctx, rc.ExprEval, stepModel.TimeoutMinutes)
defer cancelTimeOut()
err = executor(timeoutctx)
@ -213,12 +213,15 @@ func runStepExecutor(step step, stage stepStage, executor common.Executor) commo
}
}
func evaluateStepTimeout(ctx context.Context, exprEval ExpressionEvaluator, stepModel *model.Step) (context.Context, context.CancelFunc) {
timeout := exprEval.Interpolate(ctx, stepModel.TimeoutMinutes)
func evaluateTimeout(ctx context.Context, exprEval ExpressionEvaluator, timeoutMinutes string) (context.Context, context.CancelFunc) {
timeout := exprEval.Interpolate(ctx, timeoutMinutes)
if timeout != "" {
if timeOutMinutes, err := strconv.ParseInt(timeout, 10, 64); err == nil {
timeOutMinutes, err := strconv.ParseInt(timeout, 10, 64)
if err == nil {
common.Logger(ctx).Debugf("the step will stop in timeout-minutes %s", timeout)
return context.WithTimeout(ctx, time.Duration(timeOutMinutes)*time.Minute)
}
common.Logger(ctx).Errorf("timeout-minutes %s cannot be parsed and will be ignored: %w", timeout, err)
}
return ctx, func() {}
}

View file

@ -18,7 +18,8 @@ jobs:
- run: ls
- run: echo 'hello world'
- run: echo ${GITHUB_SHA} >> $(dirname "${GITHUB_WORKSPACE}")/sha.txt
- run: cat $(dirname "${GITHUB_WORKSPACE}")/sha.txt | grep ${GITHUB_SHA}
- timeout-minutes: 30
run: cat $(dirname "${GITHUB_WORKSPACE}")/sha.txt | grep ${GITHUB_SHA}
build:
runs-on: ubuntu-latest
needs: [check]

View file

@ -0,0 +1,12 @@
name: timeout-minutes
on: push
env:
TIMEOUT_MINUTES: 0
jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: ${{ env.TIMEOUT_MINUTES }}
steps:
- run: sleep 10

View file

@ -0,0 +1,12 @@
name: timeout-minutes
on: push
env:
TIMEOUT_MINUTES: 0
jobs:
check:
runs-on: ubuntu-latest
steps:
- timeout-minutes: ${{ env.TIMEOUT_MINUTES }}
run: sleep 10