Step과 Job의 차이점
Step은 무조건 순차적으로 실행되는 반면, Job은 병렬적으로 실행될 수도 있고 순서대로 실행될 수도 있다. 이 말은 Step에서 실패를 제어하기 위해 사용했던 전제인 "먼저 실행된 Step은 이후 Step 시작 전에 끝난다"가 더이상 유효하지 않다는 뜻이다. 따라서 이 전제를 맞추기 위해 추가적인 설정을 해주어야 한다.
병렬적인 Job 간의 실패 제어
일단, 병렬적인 Job A와 Job B가 있다고 해보자. B가 A의 실패를 제어하는 것은 불가능하다. 이유는 B는 A에 대한 정보가 없기 때문이다. 하나의 Job이 다른 Job에 대한 정보를 알기 위해서는 needs Context를 사용해야 하는데, 병렬적인 Job 간에는 needs에 다른 Job의 정보가 없다.
공식 문서에는 아래와 같이 나와있다.
The needs context contains outputs from all jobs that are defined as a direct dependency of the current job.
needs Context는 현재 Job에 직접 의존성이 있다고 정의된 모든 Job에 대한 outputs 정보를 가진다.
따라서 다른 Job이 실패했는지에 대해 필요한 정보가 없으므로, 병렬적인 Job 간의 실패 제어는 불가능하다.
*제어가 되어도 문제이다. Job A, B가 병렬적으로 실행되면 각 Job 실행 시점에 다른 Job이 성공했는지, 실패했는지는 랜덤이기 때문이다.
순차적인 Job 간의 실패 제어
순차적인 Job 간에는 실패 제어가 가능하다. 순차적인 Job은 앞서 실행된 Job이 성공했는지 실패했는지를 알 수 있기 때문이다. Step에서는 outputs.outcome을 통해 상태에 접근했지만 Job에서는 jobs.<job_id>.result 를 통해 상태에 접근할 수 있다.
Context Name | Type | Description |
jobs.<job_id>.result | string | Job의 실행 결과 반환. 반환 값 : success, failure, cancelled, skipped |
하지만, Job에 의존성 있는 Job 객체 정보는 needs 객체에 관리되므로, needs.<job_id>.result 로 상태에 접근할 수 있다.
예를 들어 test Job과 handle-failure Job이 있다고 해보자. handle-failure은 needs 로 test를 가지므로 test가 끝나고 수행된다. 따라서 handle-failure은 test가 성공했는지, 실패했는지에 대한 정보가 있다. 따라서 if 문을 통해 해당 정보로 이전 Job이 실패했는지 확인 후 수행하는 것이 가능하다.
handle-failure:
runs-on: ubuntu-latest
needs: [ test ]
if: failure() && needs.test.result == 'failure'
steps:
- name: Print Report
run: |
echo "This runs when test fails"
전체 코드
전체 코드는 다음과 같다. test Job 을 수행 후 handle-failure Job을 수행한다.
name: Handle Job Failure - Handled - if
on:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Check out Repository
uses: actions/checkout@v3
- name: set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Test with Gradle
id: exec-test
run: ./gradlew :app::testDebug
handle-failure:
runs-on: ubuntu-latest
needs: [ test ]
if: failure() && needs.test.result == 'failure'
steps:
- name: Print Report
run: |
echo "This runs when test fails"