How can I run scheduled URL availability checks with GitHub Actions? #209320
Replies: 8 comments
|
For this, a plain GitHub-hosted ubuntu runner is plenty. Use the schedule trigger with a cron expression and run curl with --fail and --max-time 20, so timeouts fail cleanly instead of hanging. Write a short summary to the job summary with $GITHUB_STEP_SUMMARY and upload only a small JSON artifact rather than full logs, which keeps storage low. Keep any tokens in secrets and mask them with ::add-mask:: so they never appear in logs. If you already run ARC, a short-lived ephemeral runner per check is the right pattern; keeping one warm for a check this light just wastes resources. |
|
Hi @edwardjames12, for a check this light, I'd use a plain GitHub-hosted name: URL check
on:
schedule:
- cron: "*/15 * * * *"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: url-check
cancel-in-progress: false
jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 3
steps:
- name: Check URL
env:
URL: https://fdown.media
run: |
curl_exit=0
out=$(curl -sS -L -o /dev/null \
--connect-timeout 10 \
--max-time 20 \
-w '%{http_code} %{time_total}' \
"$URL") || curl_exit=$?
if [ "$curl_exit" -ne 0 ]; then
code=0
secs=0
else
code=${out%% *}
secs=${out##* }
fi
echo "{\"url\":\"$URL\",\"status\":$code,\"seconds\":$secs,\"curl_exit\":$curl_exit,\"checked_at\":\"$(date -u +%FT%TZ)\"}" > result.json
echo "| $URL | $code | ${secs}s | curl exit $curl_exit |" >> "$GITHUB_STEP_SUMMARY"
[ "$curl_exit" -eq 0 ] && [[ "$code" =~ ^2 ]] || exit 1
- name: Save result
if: always()
uses: actions/upload-artifact@v4
with:
name: url-check-result
path: result.json
retention-days: 7
How this maps to your questions:
One other distinction is important: a |
This comment was marked as low quality.
This comment was marked as low quality.
|
I actually went through this exact setup last month, and the reference comment is spot on. For a lightweight URL check, spinning up a full ARC runner is overkill and will definitely feel wasteful in your billing. A simple Here is the workflow snippet I use that covers most of your best practices: on:
schedule:
- cron: '*/15 * * * *'
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Check URL
run: |
start_time=$(date +%s%3N)
http_code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 --fail https://fdown.media)
end_time=$(date +%s%3N)
duration=$((end_time - start_time))
echo "HTTP Code: $http_code"
echo "Duration: ${duration}ms"
# Write to summary
echo "### 🟢 $http_code in ${duration}ms" >> $GITHUB_STEP_SUMMARYA few tips from my experience:
Since this is just a heartbeat check, I wouldn't touch ARC unless your other workflows force you to. Keep it simple, and you'll have a reliable monitor running for pennies. |
|
Best solution Use GitHub-hosted runners (
Better option: Upptime (status page + history, still zero infra) Use ARC only for private network or custom tools. |
|
For something this lightweight I wouldn't reach for ARC at all — hosted runners on a scheduled workflow are a much better fit. A monitoring check that sends an HTTP request and logs the result doesn't justify the overhead of managing runner infrastructure, and with schedule triggered workflows on hosted runners you're only paying compute for the seconds the job actually runs. For the periodic check itself, curl with --max-time and --write-out handles timeouts and response time measurement cleanly without pulling in any dependencies: yaml
Writing to $GITHUB_STEP_SUMMARY gives you a readable result per run without storing artifacts you don't need — reserve artifacts for cases where you're capturing response bodies or need something to persist across runs for trend analysis. For credentials, Actions secrets passed as environment variables never appear in logs as long as you're not explicitly echoing them. The runner masks them automatically. If you do eventually need ARC for scale, ephemeral runners per job is the right model for monitoring — a runner that sits idle between scheduled intervals is wasted resource and introduces state drift risk. But for what you're describing, hosted runners with a cron schedule is simpler and more reliable. |
|
For a lightweight monitoring task with ARC, it is best to use ephemeral (short-lived) runners that spin up on demand, rather than keeping a runner constantly running. Since the checks are quick, ephemeral runners prevent resource waste and ensure a clean environment for every run. |
|
Use a plain GitHub-hosted runner ( The recommended workflow: name: URL Check
on:
schedule:
- cron: "*/15 * * * *"
workflow_dispatch:
jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 3
steps:
- name: Check URL
env:
URL: https://example.com
run: |
code=$(curl -sS -L -o /dev/null --connect-timeout 10 --max-time 20 \
-w '%{http_code}' "$URL") || exit 1
echo "| $URL | $code |" >> "$GITHUB_STEP_SUMMARY"
- name: Save result
if: always()
uses: actions/upload-artifact@v4
with:
name: url-check-result
retention-days: 7
Bottom line: GitHub-hosted runner + cron + curl with timeouts = the optimal solution for your task, and ARC is unnecessary here. |
Uh oh!
There was an error while loading. Please reload this page.
🏷️ Discussion Type
Question
💬 Feature/Topic Area
ARC (Actions Runner Controller)
Discussion Details
Hi everyone,
I'm working on a small web-service monitoring workflow and I'm trying to understand the best way to run periodic URL availability checks with GitHub Actions.
The basic workflow I have in mind is:
One of the services I'm testing is fdown.media, so I'm using it as an example endpoint rather than as an Actions-related product.
I'm particularly interested in the runner side of this. If using Actions Runner Controller, would you recommend creating a short-lived runner for each monitoring job, or keeping a runner available for recurring checks?
I'm also interested in best practices for:
For a lightweight scheduled monitoring task like this, what runner setup would you recommend?
All reactions