Skip to content

Restart Preempted Libc++ Workflow #2

Restart Preempted Libc++ Workflow

Restart Preempted Libc++ Workflow #2

name: Restart Preempted Libc++ Workflow
# The libc++ builders run on preemptable VMs, which can be shutdown at any time.
# This workflow identifies when a workflow run was canceled due to the VM being preempted,
# and restarts the workflow run.
# We identify a canceled workflow run by checking the annotations of the check runs in the check suite,
# which should contain the message "The runner has received a shutdown signal."
# Note: If a job is both preempted and also contains a non-preemption failure, we do not restart the workflow.
on:
workflow_run:
workflows: [Build and Test libc\+\+]
types:
- completed
permissions:
contents: read
jobs:
restart:
if: github.repository_owner == 'llvm' && (github.event.workflow_run.conclusion == 'failure' || github.event.workflow_run.conclusion == 'cancelled')
name: "Restart Job"
permissions:
statuses: read
checks: read
actions: write
runs-on: ubuntu-latest
steps:
- name: "Restart Job"
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1
with:
script: |
const failure_regex = /Process completed with exit code 1./
const preemption_regex = /The runner has received a shutdown signal/
console.log('Listing check runs for suite')
const check_suites = await github.rest.checks.listForSuite({
owner: context.repo.owner,
repo: context.repo.repo,
check_suite_id: context.payload.workflow_run.check_suite_id
})
check_run_ids = [];
for (check_run of check_suites.data.check_runs) {
console.log('Checking check run: ' + check_run.id);
if (check_run.status != 'completed') {
console.log('Check run was not completed. Skipping.');
continue;
}
if (check_run.conclusion != 'failure' && check_run.conclusion != 'cancelled') {
console.log('Check run had conclusion: ' + check_run.conclusion + '. Skipping.');
continue;
}
check_run_ids.push(check_run.id);
}
has_preempted_job = false;
for (check_run_id of check_run_ids) {
console.log('Listing annotations for check run: ' + check_run_id);
annotations = await github.rest.checks.listAnnotations({
owner: context.repo.owner,
repo: context.repo.repo,
check_run_id: check_run_id
})
for (annotation of annotations.data) {
if (annotation.annotation_level != 'failure') {
continue;
}
const preemption_match = annotation.message.match(preemption_regex);
if (preemption_match != null) {
console.log('Found preemption message: ' + annotation.message);
has_preempted_job = true;
}
const failure_match = annotation.message.match(failure_regex);
if (failure_match != null) {
// We only want to restart the workflow if all of the failures were due to preemption.
// We don't want to restart the workflow if there were other failures.
console.log('Choosing not to rerun workflow because we found a non-preemption failure');
console.log('Failure message: ' + annotation.message);
return;
}
}
}
if (!has_preempted_job) {
console.log('No preempted jobs found. Not restarting workflow.');
return;
}
console.log("Restarted workflow: " + context.payload.workflow_run.id);
await github.rest.actions.reRunWorkflowFailedJobs({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id
})