Is it possible to cancel job automatically when specific job is approved?

I have two approval jobs called test-qa and test-develop, and the level of jobs is same. I want to cancel other job when I approved specific job. Is it possible?

For example,

  1. I approved test-qa job → test-develop job is canceled or failed
  2. I approved test-develop job → test-qa job is canceled or failed

If it is possible, how can I apply this feature in config.yml ?

THX!

Hi @baeharam,

Although it isn’t possible to directly cancel an approval-type job, you can however cancel the “on_hold” workflow containing the approval job.

Assuming you have 2 defined jobs (each with their own executor, steps, …etc) in your config.yml, here are suggestions on how to proceed.

Note: You’ll need to create an environment variable containing your personal API token.

 

version: 2.1

jobs:
  job-qa:
    .....
    .....
    .....
    .....
                                                     
  job-develop:
    .....
    .....
    .....
    .....
                                                     
  cancel-other-hold:
    docker:
      - image: circleci/python
    steps:
      - run:
          name: Cancelling the other on_hold workflow
          command: |
              other_on_hold_id=$(curl -G "https://circleci.com/api/v2/pipeline/<<pipeline.id>>/workflow" -H "Circle-Token: $MyToken"|jq -rs --arg CIRCLE_WORKFLOW_ID "$CIRCLE_WORKFLOW_ID" '.[].items[]|select(.status == "on_hold")|select(.id != $CIRCLE_WORKFLOW_ID)|.id')
                    echo $other_on_hold_id
                    curl -X POST "https://circleci.com/api/v2/workflow/${other_on_hold_id}/cancel" -H "Circle-Token: ${MyToken}"
              
                   
workflows:
  qa:
    jobs:
      - job-qa
      - test-qa:
          type: approval
          requires:
            - job-qa
      - cancel-other-hold:
          requires:
            - test-qa
                
  develop:
    jobs:
      - job-develop
      - test-develop:
          type: approval
          requires:
            - job-develop
      - cancel-other-hold:
          requires:
            - test-develop

 

You could also use a parameterized job:

version: 2.1

jobs:
  job-qa:
    .....
    .....
    .....
    .....
                                                     
  job-develop:
    .....
    .....
    .....
    .....
   
cancel-on-hold: # defines a parameterized job
    description: A job that just cancels a workflow
    parameters:
      other_wf:
        type: string
    docker:
      - image: circleci/python
    steps:
      - run:
          name: Cancelling the other on_hold workflow
          command: |
              other_on_hold_id=$(curl -G "https://circleci.com/api/v2/pipeline/<<pipeline.id>>/workflow" -H "Circle-Token: $MyToken"|jq -rs --arg parameters.other_wf $parameters.other_wf '.[].items[]|select(.name == "<< parameters.other_wf >>")|.id')
              curl -X POST "https://circleci.com/api/v2/workflow/$other_on_hold_id/cancel" -H "Circle-Token: $MyToken"
              
                   
workflows:
  qa:
    jobs:
      - job-qa
      - test-qa:
          type: approval
          requires:
            - job-qa
      - cancel-on-hold:
          other_wf: develop
          requires:
            - test-qa
                
  develop:
    jobs:
      - job-develop
      - test-develop:
          type: approval
          requires:
            - job-develop
      - cancel-on-hold:
          other_wf: qa
          requires:
            - test-develop

 

Also, depending on the jobs included in your actual config.yml, you could use post-steps, which would eliminate the need for the additional job.
But keep in mind that post-steps do not work if they directly follow an approval-type job.

Here’s an example of post-steps you could add:

          post-steps:
            - run:
                name: Cancelling the other "on_hold" workflow
                command: |
                    other_on_hold_id=$(curl -G "https://circleci.com/api/v2/pipeline/<<pipeline.id>>/workflow" -H "Circle-Token: $MyToken"|jq -rs --arg CIRCLE_WORKFLOW_ID "$CIRCLE_WORKFLOW_ID" '.[].items[]|select(.status == "on_hold")|select(.id != $CIRCLE_WORKFLOW_ID)|.id')
                    echo $other_on_hold_id
                    curl -X POST "https://circleci.com/api/v2/workflow/${other_on_hold_id}/cancel" -H "Circle-Token: ${MyToken}"
1 Like

@yannCI

Sorry for the late response, it took many days to apply.
Your idea is great, but on_hold job doesn’t have job_number as response. Therefore, I have to approve approval job and cancel that job. I think it is best for this case. How do you think?

Hi @baeharam,

Indeed, approval jobs don’t have a job number, hence my advice to cancel the whole workflow that contains the approval job.

@yannCI

Ah… I understood. But, I cannot cancel whole workflow containing on_hold job. Is there other way to only cancel on_hold job?

Hi @baeharam,

As you previously pointed out, it is not possible to directly cancel an on_hold job as it doesn’t have a job_number.

You could add a workflow that contains the on_hold job and another job that sets the value of a parameter, and have the execution of downstream workflows conditioned by that parameter.

Then if the workflow containing the on_hold job is cancelled, the downstream workflows won’t be executed.

@yannCI

Sorry for late response.
I think I have to change CI flow for this solution. Anyway, this is the best solution for on_hold job.
Thanks.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.