Is there a way to cancel a running workflow within one of its jobs?

I have a workflow with 4 jobs defined.

The first job essentially returns a boolean and depending on that boolean the next 2 jobs will run in parallel.

Following successful completion of those 2 jobs the final one runs.

I was going to use Job status check functions with jobs 2 and 3 to decide whether they should run or not but I dont want to set the state of job 1 to failed as that is misleading. It has not failed, its just the outcome of the check it has performed is false and so the workflow should stop here. I had thought of cancelling the workflow if the job1 result is false but to my knowledge there is no way to programatically cancel a running workflow. Is there a suggested way to handle a case like this? I guess I could save a file with the outcome of job 1 and use the upload artifact action but that seems like a hugely bloated way for what I’m trying to achieve

1 Like

Take a look at https://github.com/andymckay/cancel-action.

That Action will cancel the current run. It uses the new Actions API.

2 Likes

May be you can reference the workarond I mentioned in this ticket that using artifact and output parameter to pass the status from the first job.

Here is another way using the same API via actions/github-script (convenient since the check was already using it in my case).

Note that cancellation is not immediate (takes about 15 seconds), so I added a sleep in the case we want to cancel to not mark any step as “failed”. It’s mostly a UI thing because the whole run is reported as cancelled even without the sleep.

Make sure to have a safeguard below though (named Should build? here).

    - uses: actions/github-script@v2
      id: check
      with:
        script: |
          const { owner, repo } = context.repo
          if (myCondition) {
            console.log('Cancelling ...');
            const run_id = "${{ github.run_id }}";
            await github.actions.cancelWorkflowRun({ owner, repo, run_id });
            return 'stop'
          } else {
            return 'build'
          }
        result-encoding: string
    - name: Waiting for cancellation
      run: sleep 60
      if: steps.check.outputs.result == 'stop'
    - name: Should build?
      run: test "${{ steps.check.outputs.result }}" = "build"