Run dependent job even on failure?

Hi,

I’m looking to split up a CD process into multiple jobs, some of which can run in parallel, and then aggregate the results in a final job. I have a dependency graph that looks like:

     A
   /   \
  B     C
   \   /
     D

A creates a deployment using the GitHub API. B and C are jobs run in parallel related to deploying the application. And D is a status aggregator that should change the state of the whole deployment from pending to success or failure. I don’t want B or C to take whatever action on failure because it may be duplicated. In the case of updating a GitHub deployment, that’s not a huge deal. For other actions, however, it would be problematic.

Since deployments only happen when certain branches or tags are updated, A has an if guard on github.ref. I don’t need the guards elsewhere because the dependency hierarchy is established and the the whole job graph will show as skipped if the ref doesn’t match. That part works very nicely.

The problem I’m having is getting D to work the same way. I want to run it even if B or C fail, but I only want to run it when A runs. I can’t find a way to ignore the failure status of its parents other than using if: always(). I’ve tried to use a different gate expression (e.g., if: ${{ needs.A.outputs.deployment_id }}), but if I use anything other than if: always(), the job won’t run if a parent fails.

Is there any way to tell D to ignore failures in B and C? NB: I do not want to tell B and C to ignore failures because I do want to show them as failed in the UI in the event that they fail. I just also want to run D in that case. I currently collect the output status for both jobs, so when D runs I can tell which jobs succeeded and which failed:

outputs:
  job_status: ${{ job.status }}

Alternatively, is there a way for me to tell D it should always run if A runs?

Hi @nirvdrum,

You can use a combined if expression in JobD. Code sample as below:

  jobD:
    needs: [jobA, jobB, jobC]                                            #depend on jobA,B,C
    if: "always()&&(needs.jobA.outputs.job_status=='success')"   # check jobA outputs as well.

the workflow will ignore jobB, jobC status and run based on jobA succeeds. Please change the jobA needs outputs according to your situation.

Thanks.

That worked. Thanks! I tried many different variations of that if condition and never would have thought to combine always() with another condition.