Nightly Dispatcher #241
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Nightly Dispatcher | |
| permissions: | |
| actions: write | |
| contents: read | |
| on: | |
| schedule: | |
| # Run main branch at 10:00 PM (22:00 UTC) | |
| - cron: '0 22 * * *' | |
| # Run version/mx/10 branch at 4:00 AM UTC | |
| - cron: '0 4 * * *' | |
| jobs: | |
| # This job determines which branch to target based on the schedule | |
| determine-target: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| target-branch: ${{ steps.set-branch.outputs.branch }} | |
| run-name: ${{ steps.set-branch.outputs.run-name }} | |
| steps: | |
| - id: set-branch | |
| run: | | |
| if [[ "${{ github.event.schedule }}" == "0 22 * * *" ]]; then | |
| echo "branch=main" >> $GITHUB_OUTPUT | |
| echo "run-name=Nightly Main Branch Pipeline" >> $GITHUB_OUTPUT | |
| else | |
| echo "branch=version/mx/10" >> $GITHUB_OUTPUT | |
| echo "run-name=Nightly version/mx/10 Branch Pipeline" >> $GITHUB_OUTPUT | |
| fi | |
| # This single job handles dispatching to the correct branch | |
| dispatch-pipeline: | |
| needs: determine-target | |
| runs-on: ubuntu-latest | |
| outputs: | |
| run-id: ${{ steps.trigger.outputs.run_id }} | |
| target-branch: ${{ needs.determine-target.outputs.target-branch }} | |
| steps: | |
| - name: "Trigger Native Pipeline on ${{ needs.determine-target.outputs.target-branch }}" | |
| id: trigger | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7 | |
| with: | |
| script: | | |
| const targetBranch = '${{ needs.determine-target.outputs.target-branch }}'; | |
| const runName = '${{ needs.determine-target.outputs.run-name }}'; | |
| console.log(`Triggering workflow on branch: ${targetBranch}`); | |
| const response = await github.rest.actions.createWorkflowDispatch({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| workflow_id: 'NativePipeline.yml', | |
| ref: targetBranch, | |
| inputs: { | |
| run_name: runName, | |
| workspace: '*-native' | |
| } | |
| }); | |
| console.log('Workflow dispatch triggered successfully'); | |
| // Wait longer and find the correct run | |
| let runId = null; | |
| let attempts = 0; | |
| const maxAttempts = 18; // 3 minutes | |
| while (!runId && attempts < maxAttempts) { | |
| await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds | |
| attempts++; | |
| console.log(`Attempt ${attempts}/${maxAttempts} to find triggered run...`); | |
| try { | |
| const runs = await github.rest.actions.listWorkflowRuns({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| workflow_id: 'NativePipeline.yml', | |
| branch: targetBranch, | |
| per_page: 10 | |
| }); | |
| // Find run created in the last 10 minutes | |
| const tenMinutesAgo = new Date(); | |
| tenMinutesAgo.setMinutes(tenMinutesAgo.getMinutes() - 10); | |
| const recentRun = runs.data.workflow_runs.find(run => { | |
| const runDate = new Date(run.created_at); | |
| return runDate > tenMinutesAgo && run.event === 'workflow_dispatch'; | |
| }); | |
| if (recentRun) { | |
| runId = recentRun.id; | |
| console.log(`Found triggered run ID: ${runId}`); | |
| break; | |
| } | |
| } catch (error) { | |
| console.log(`Error finding run: ${error.message}`); | |
| } | |
| } | |
| if (!runId) { | |
| console.log('Could not find the triggered workflow run - will continue without monitoring'); | |
| core.setOutput('dispatch_success', 'false'); | |
| core.setOutput('run_id', ''); | |
| return; | |
| } | |
| core.setOutput('dispatch_success', 'true'); | |
| core.setOutput('run_id', runId); | |
| return runId; | |
| auto-retry: | |
| needs: [dispatch-pipeline, determine-target] | |
| if: always() && needs.dispatch-pipeline.outputs.run-id != '' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: "Monitor and retry failed jobs" | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7 | |
| with: | |
| script: | | |
| const runId = '${{ needs.dispatch-pipeline.outputs.run-id }}'; | |
| const targetBranch = '${{ needs.dispatch-pipeline.outputs.target-branch }}'; | |
| if (!runId || runId === 'null' || runId === '') { | |
| console.log('No run ID available from dispatch job - skipping monitoring'); | |
| return; | |
| } | |
| console.log(`Starting monitoring for run ID: ${runId} on branch ${targetBranch}`); | |
| // Poll for completion with timeout | |
| let run; | |
| let pollAttempts = 0; | |
| const maxPollAttempts = 240; // 4 hours max | |
| do { | |
| if (pollAttempts >= maxPollAttempts) { | |
| console.log('Monitoring timeout reached (4 hours). Stopping.'); | |
| return; | |
| } | |
| await new Promise(resolve => setTimeout(resolve, 60000)); // Wait 1 minute | |
| pollAttempts++; | |
| try { | |
| run = await github.rest.actions.getWorkflowRun({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| run_id: runId | |
| }); | |
| console.log(`Poll #${pollAttempts}: Run status: ${run.data.status}, conclusion: ${run.data.conclusion || 'N/A'}, attempt: ${run.data.run_attempt}`); | |
| } catch (error) { | |
| console.log(`Error getting run status: ${error.message}`); | |
| continue; | |
| } | |
| } while (run.data.status === 'in_progress' || run.data.status === 'queued'); | |
| // Check if we should retry | |
| if (run.data.conclusion === 'failure') { | |
| console.log(`Pipeline failed on attempt ${run.data.run_attempt}. Checking if retry needed...`); | |
| // Only retry if this is the first attempt | |
| if (run.data.run_attempt === 1) { | |
| console.log(`Triggering retry for failed jobs on branch ${targetBranch}...`); | |
| try { | |
| await github.rest.actions.reRunWorkflowFailedJobs({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| run_id: runId | |
| }); | |
| console.log('Retry triggered successfully for failed jobs only.'); | |
| } catch (error) { | |
| console.error(`Failed to trigger retry: ${error.message}`); | |
| console.log('Detailed error:', JSON.stringify(error, null, 2)); | |
| } | |
| } else { | |
| console.log('This was already a retry attempt. Not retrying again.'); | |
| } | |
| } else if (run.data.conclusion === 'success') { | |
| console.log('Pipeline completed successfully!'); | |
| } else { | |
| console.log(`Pipeline completed with conclusion: ${run.data.conclusion}`); | |
| } |