Steps to reproduce
- Have three
Maestro (local) runs overlap, which happens routinely on a weekday morning: run A's Maestro test suite job is executing, run B finishes Build APK and enters the maestro-test group as pending, then run C finishes Build APK.
- Look at run B: its
Maestro test suite job is cancelled with 0 steps run, at the second C's build completes. C then starts the moment A finishes.
Two instances from the last week (all times UTC, run pages at https://github.com/element-hq/element-x-android/actions/runs/<id>):
| date |
A: running |
B: pending, then cancelled |
C: arrives and takes B's place |
| 2026-08-31 |
33380732765, Maestro 10:13:41 to 10:24:03 |
33380774144 (#7434 ci/project-isolation), pending from 10:16:55, cancelled 10:20:28 |
33381138968, Build APK completed 10:20:27, Maestro 10:24:05 |
| 2026-09-02 |
33617290601, Maestro 10:12:10 to 10:24:31 |
33617864980 (sync-localazy), pending from 10:15:00, cancelled 10:16:14 |
33618091064, Build APK completed 10:16:13, Maestro 10:24:35 |
This is GitHub's documented default for a concurrency group: "At most one running job or workflow in a concurrency group at any time. [...] By default, any existing pending job or workflow in the same concurrency group will be canceled and the new queued job or workflow will take its place." (https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs)
The group is declared at .github/workflows/maestro-local.yml L76-79 (develop 66c5028, 2026-09-04):
# Allow only one to run at a time, since they use the same environment.
# Otherwise, tests running in parallel can break each other.
concurrency:
group: maestro-test
Outcome
What did you expect?
Runs wait their turn. One-at-a-time is the right constraint while the suite drives a single shared matrix.org account, as the comment says, but every PR should still end up with a Maestro verdict for its commit.
What happened instead?
- Run B's PR gets no Maestro result for that commit at all, and nothing re-runs it. The workflow shows
cancelled, which reads as "nobody ran it" rather than "another PR bumped it".
- B's ~10-minute
Build APK had already been paid for when the Maestro job was cancelled.
- Whichever run happens to be pending when the next PR's build finishes loses, so on a busy morning the same PR can be bumped repeatedly.
Proposed fix
One line. GitHub's queue property on the concurrency object exists for exactly this: "To allow more than one pending job or workflow run to wait in the same concurrency group, use the optional queue property." single is the default (at most one pending); max allows up to 100 pending.
concurrency:
group: maestro-test
queue: max
Pending jobs do not occupy a runner, so this adds no runner-minutes; it just stops dropping runs. Still no cancel-in-progress here, since that would cancel another PR's executing run. (The docs note ordering is FIFO by the time each run started waiting, not strictly guaranteed, which is fine for this use.)
A related, separate observation: PRs from forks also take a turn in this group only to fail immediately on the missing MAESTRO_PASSWORD secret, so they add contention for nothing. See #7653.
Your phone model
n/a (CI: reactivecircus/android-emulator-runner, pixel_7_pro, API 33, x86_64)
Operating system version
n/a
Application version and app store
develop @ 66c5028 (CI build of :app:assembleGplayDebug)
Homeserver
matrix.org (the CI test account)
Will you send logs?
No (the CI run pages linked above contain everything)
Will you submit a Pull Request?
No
Steps to reproduce
Maestro (local)runs overlap, which happens routinely on a weekday morning: run A'sMaestro test suitejob is executing, run B finishesBuild APKand enters themaestro-testgroup as pending, then run C finishesBuild APK.Maestro test suitejob is cancelled with 0 steps run, at the second C's build completes. C then starts the moment A finishes.Two instances from the last week (all times UTC, run pages at
https://github.com/element-hq/element-x-android/actions/runs/<id>):ci/project-isolation), pending from 10:16:55, cancelled 10:20:28sync-localazy), pending from 10:15:00, cancelled 10:16:14This is GitHub's documented default for a concurrency group: "At most one running job or workflow in a concurrency group at any time. [...] By default, any existing
pendingjob or workflow in the same concurrency group will be canceled and the new queued job or workflow will take its place." (https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/control-the-concurrency-of-workflows-and-jobs)The group is declared at
.github/workflows/maestro-local.ymlL76-79 (develop66c5028, 2026-09-04):Outcome
What did you expect?
Runs wait their turn. One-at-a-time is the right constraint while the suite drives a single shared matrix.org account, as the comment says, but every PR should still end up with a Maestro verdict for its commit.
What happened instead?
cancelled, which reads as "nobody ran it" rather than "another PR bumped it".Build APKhad already been paid for when the Maestro job was cancelled.Proposed fix
One line. GitHub's
queueproperty on the concurrency object exists for exactly this: "To allow more than onependingjob or workflow run to wait in the same concurrency group, use the optionalqueueproperty."singleis the default (at most one pending);maxallows up to 100 pending.Pending jobs do not occupy a runner, so this adds no runner-minutes; it just stops dropping runs. Still no
cancel-in-progresshere, since that would cancel another PR's executing run. (The docs note ordering is FIFO by the time each run started waiting, not strictly guaranteed, which is fine for this use.)A related, separate observation: PRs from forks also take a turn in this group only to fail immediately on the missing
MAESTRO_PASSWORDsecret, so they add contention for nothing. See #7653.Your phone model
n/a (CI: reactivecircus/android-emulator-runner, pixel_7_pro, API 33, x86_64)
Operating system version
n/a
Application version and app store
develop@ 66c5028 (CI build of:app:assembleGplayDebug)Homeserver
matrix.org (the CI test account)
Will you send logs?
No (the CI run pages linked above contain everything)
Will you submit a Pull Request?
No