I've got a workflow with 2 jobs.
name
and type
) as outputtype
to be executed.jobs:
orchestration:
runs-on: ubuntu-latest
outputs:
tasks: ${{ steps.tasks.outputs.tasks }}
steps:
- name: Setup Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Build Tasks Array
id: tasks
run: |
import json
import os
tasks = []
for i in range(1, 20):
task_type = "TYPE1" if i % 3 == 1 else ("TYPE2" if i % 3 == 2 else "TYPE3")
tasks.append({"taskId": f"task{i}", "type": task_type})
print("Tasks list:", tasks)
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
f.write(f"tasks={json.dumps(tasks)}\n")
shell: python
process:
runs-on: ubuntu-latest
needs: [orchestration]
strategy:
matrix:
tasks: ${{fromJson(needs.orchestration.outputs.tasks)}}
steps:
- if: contains( matrix.tasks.type , 'TYPE1')
uses: owner/action-type1@v1
with:
TASK_ID: ${{ matrix.tasks.taskId }}
- if: contains( matrix.tasks.type , 'TYPE2')
uses: owner/action-type2@v1
with:
TASK_ID: ${{ matrix.tasks.taskId }}
- if: contains( matrix.tasks.type , 'TYPE3')
uses: owner/action-type3@v1
with:
TASK_ID: ${{ matrix.tasks.taskId }}
As shared in the example above, I use matrix strategy to run the second job, according to the output from the first job.
However, the order in which the matrix jobs are executed import here, and I would like them to run following the same order as the list generated on the first job: task1 --> task2 --> task3 ...
How can I guarantee matrix strategy jobs are executed in a specific sequence on GitHub Actions?
According to the official documentation:
The order of the variables in the matrix determines the order in which the jobs are created.
However, when running in parallel, the strategy matrix order is not respected (task 10 can run before task 1).
After some researches, I found this Github Issue regarding the strategy matrix order being broken, as well as this blog post about sequential deploy.
As shared in the links above, the solution seems to use the strategy.matrix
configuration max-parallel: 1
, to force the matrix jobs to run 1 by 1 following the list informed.
Example:
strategy:
matrix:
stage: ['development', 'integration', 'production']
# When set to true, GitHub cancels all in-progress jobs if any matrix job fails.
fail-fast: true
# The maximum number of jobs that can run simultaneously
max-parallel: 1
I've made various tests with up to 100 tasks using the minimal reproducible example in the question, generating logs with timestamp to check the time each job has been running as saving it as artifacts. The final output from the log seems to confirm the order is respected.
Workflow run:
Logs generated:
Task type: TYPE1; Task name: task1; Timestamp: 2023-09-06 18:23:44
Task type: TYPE2; Task name: task2; Timestamp: 2023-09-06 18:24:23
Task type: TYPE3; Task name: task3; Timestamp: 2023-09-06 18:25:04
Task type: TYPE1; Task name: task4; Timestamp: 2023-09-06 18:25:34
Task type: TYPE2; Task name: task5; Timestamp: 2023-09-06 18:26:11
Task type: TYPE3; Task name: task6; Timestamp: 2023-09-06 18:26:45
Task type: TYPE1; Task name: task7; Timestamp: 2023-09-06 18:27:25
Task type: TYPE2; Task name: task8; Timestamp: 2023-09-06 18:28:01
Task type: TYPE3; Task name: task9; Timestamp: 2023-09-06 18:28:35
Task type: TYPE1; Task name: task10; Timestamp: 2023-09-06 18:29:06
Task type: TYPE2; Task name: task11; Timestamp: 2023-09-06 18:29:41
Task type: TYPE3; Task name: task12; Timestamp: 2023-09-06 18:30:11
Task type: TYPE1; Task name: task13; Timestamp: 2023-09-06 18:30:50
Task type: TYPE2; Task name: task14; Timestamp: 2023-09-06 18:31:28
Task type: TYPE3; Task name: task15; Timestamp: 2023-09-06 18:32:01
Task type: TYPE1; Task name: task16; Timestamp: 2023-09-06 18:32:36
Task type: TYPE2; Task name: task17; Timestamp: 2023-09-06 18:33:14
Task type: TYPE3; Task name: task18; Timestamp: 2023-09-06 18:33:50
Task type: TYPE1; Task name: task19; Timestamp: 2023-09-06 18:34:19
Task type: TYPE2; Task name: task20; Timestamp: 2023-09-06 18:34:55
Task type: TYPE3; Task name: task21; Timestamp: 2023-09-06 18:35:35
Task type: TYPE1; Task name: task22; Timestamp: 2023-09-06 18:36:07
Task type: TYPE2; Task name: task23; Timestamp: 2023-09-06 18:36:41
Task type: TYPE3; Task name: task24; Timestamp: 2023-09-06 18:37:12
Task type: TYPE1; Task name: task25; Timestamp: 2023-09-06 18:37:43
...
Task type: TYPE2; Task name: task98; Timestamp: 2023-09-06 19:21:19
Task type: TYPE3; Task name: task99; Timestamp: 2023-09-06 19:21:51
To answer the question, the solution in the second job would be to use
process:
runs-on: ubuntu-latest
needs: [orchestration]
strategy:
matrix:
tasks: ${{fromJson(needs.orchestration.outputs.tasks)}}
fail-fast: true
max-parallel: 1