mirror of
https://github.com/0xMarcio/cve.git
synced 2026-10-27 16:51:03 +00:00
Keep the hourly refresh on GitHub with a pacemaker chain
GitHub's cron scheduler creates this repository's scheduled runs four to five hours late and drops the slots in between, so the hourly Hot CVEs refresh cannot come from a cron. A workflow_dispatch call creates a run within seconds, so a pacemaker workflow now sleeps until the next :05, fires the refresh and its own successor, and keeps time by itself. Its cron only restarts the chain if a link fails. Hot CVEs loses its cron and the gate that was there to coexist with an external trigger; nothing outside GitHub is involved any more.
This commit is contained in:
1 parent
8848875256
commit
82936168a5
2 files changed
+39
-44
No files matched your search
@@ -1,15 +1,9 @@
|
||||
name: Hot CVEs List
|
||||
|
||||
# The hourly trigger is a systemd timer on the VPS calling workflow_dispatch:
|
||||
# GitHub's own scheduler creates cron runs four to five hours late and drops
|
||||
# the slots in between. The cron below is the fallback and the watchdog. It
|
||||
# yields while the trigger is alive, takes over when it is not, and fails
|
||||
# loudly once the trigger has been dead for three hours so the failure email
|
||||
# says why.
|
||||
# Fired every hour at :05 by pacemaker.yml. No cron here: GitHub's scheduler
|
||||
# creates cron runs hours late, which is the whole reason the pacemaker exists.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '7 * * * *'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -20,37 +14,7 @@ concurrency:
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
gate:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
run: ${{ steps.check.outputs.run }}
|
||||
stale: ${{ steps.check.outputs.stale }}
|
||||
steps:
|
||||
- name: Yield to the hourly trigger while it is alive
|
||||
id: check
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
if [ "$GITHUB_EVENT_NAME" != "schedule" ]; then
|
||||
echo "run=true" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
last=$(gh api "repos/$GITHUB_REPOSITORY/commits?per_page=30" \
|
||||
--jq 'map(select(.commit.message | startswith("Trending CVEs update")))[0].commit.committer.date')
|
||||
age=$(( $(date -u +%s) - $(date -u -d "${last:-1970-01-01T00:00:00Z}" +%s) ))
|
||||
echo "Last trending refresh: ${last:-none}, $((age / 60)) minutes ago"
|
||||
if [ "$age" -lt 3300 ]; then
|
||||
echo "Fresh enough, the hourly trigger is doing its job"
|
||||
exit 0
|
||||
fi
|
||||
echo "run=true" >> "$GITHUB_OUTPUT"
|
||||
if [ "$age" -gt 10800 ]; then
|
||||
echo "stale=true" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
ScheduledRun:
|
||||
needs: gate
|
||||
if: needs.gate.outputs.run == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -124,9 +88,3 @@ jobs:
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: gh workflow run site.yml --ref main
|
||||
|
||||
- name: Fail loudly when the hourly trigger is dead
|
||||
if: needs.gate.outputs.stale == 'true'
|
||||
run: |
|
||||
echo "::error::No trending refresh for over three hours: the external hourly trigger is not firing"
|
||||
exit 1
|
||||
@@ -0,0 +1,37 @@
|
||||
name: Pacemaker
|
||||
|
||||
# GitHub's cron scheduler creates this repository's scheduled runs four to
|
||||
# five hours late and drops the slots in between, so the hourly refresh cannot
|
||||
# come from a cron. A workflow_dispatch call creates a run within seconds, so
|
||||
# each pacemaker run sleeps until the next :05, fires the Hot CVEs refresh and
|
||||
# its own successor, and the chain keeps time by itself. The cron below only
|
||||
# restarts the chain if a link ever fails; while the chain is alive the
|
||||
# concurrency group holds the extra run back and the next link cancels it.
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '7 * * * *'
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
|
||||
concurrency:
|
||||
group: pacemaker
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
tick:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 70
|
||||
steps:
|
||||
- name: Sleep until the next :05, then fire the hourly refresh
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
now=$(date -u +%s)
|
||||
next=$(( now / 3600 * 3600 + 300 ))
|
||||
[ "$next" -gt "$now" ] || next=$(( next + 3600 ))
|
||||
echo "Sleeping $(( (next - now) / 60 )) minutes until $(date -u -d @"$next" +%H:%M) UTC"
|
||||
sleep $(( next - now ))
|
||||
gh workflow run hot_cves.yml --ref main
|
||||
gh workflow run pacemaker.yml --ref main
|
||||
Reference in new issue
Block a user