1
0
Fork 0
mirror of https://code.forgejo.org/forgejo/runner.git synced 2025-09-15 18:57:01 +00:00

fix: enforce job.<job-id>.timeout-minutes (#982)

- 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

---

Manually verified to work as expected https://v13.next.forgejo.org/earl-warren/testtimeout-minutes/actions/runs/3/jobs/0/attempt/1

```yaml
on: [push]
jobs:
  test:
    runs-on: docker
    timeout-minutes: 1
    steps:
      - run: |
          set -x
          while : ; do
            sleep 30
          done
```

![image](/attachments/047ddd15-7109-4931-a6ed-43073e4d31f9)

<!--start release-notes-assistant-->
<!--URL:https://code.forgejo.org/forgejo/runner-->
- bug fixes
  - [PR](https://code.forgejo.org/forgejo/runner/pulls/982): <!--number 982 --><!--line 0 --><!--description Zml4OiBlbmZvcmNlIGpvYi48am9iLWlkPi50aW1lb3V0LW1pbnV0ZXM=-->fix: enforce job.<job-id>.timeout-minutes<!--description-->
<!--end release-notes-assistant-->

Reviewed-on: https://code.forgejo.org/forgejo/runner/pulls/982
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.code.forgejo.org>
Co-authored-by: Earl Warren <contact@earl-warren.org>
Co-committed-by: Earl Warren <contact@earl-warren.org>
This commit is contained in:
Earl Warren 2025-09-11 14:43:26 +00:00 committed by earl-warren
parent 933667bdf1
commit 02a51c0a21
No known key found for this signature in database
GPG key ID: F128CBE6AB3A7201
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