News

Because I don't do social media

Using GitHub Actions as a (web)cron

Suggestions on using the schedule property

July, 2020

tl;dr; Check out an example of a web cron on GitHub.

GitHub Actions are pretty great. I use them to run tests for every git push, and make sure that tests pass before a PR can be merged. Before that I've used TravisCI, CircleCI, and CodeShip. While there's nothing necessarily wrong with them (they work, are stable, well-documented, and have free and paid plans), I like the simplification of keeping everything in GitHub, which is where the code has always been, anyway.

For many personal and professional cases, I have some jobs that need to run on a schedule, and for simplicity (and also because most of them are "serverless" now), they can usually be triggered with a GET or POST request, with some sort of authentication token, and I've used EasyCron for over a year for that, and have no complaints at all (it works, it's simple, and has free and paid plans).

However, pretty much like CI, the idea of getting such jobs to not have to be "outsourced" (especially with the "secret" variables) and simply run from within where the code and deployment exists was just too enticing. Luckily, it's really easy and you just need to add something like:

on:
  schedule:
    # Every Monday at 1:05am UTC
    - cron: '5 1 * * 1'

On your GitHub workflow file.

For making an HTTP request, you can use curl! Something like this:

- run: |
  curl -X "POST" "https://example.com/api/jobs/cleanup" \
    -H 'Content-Type: application/json; charset=utf-8' \
    -H 'Authorization: Bearer ${{ secrets.JOB_API_KEY }}' \
    -d $'{ "someKey": "someValue" }'

To add secrets, you just need to use GitHub's secrets tab in your repo.

All together, a simple job workflow file can look like:

name: Job - Cleanup

on:
  workflow_dispatch:
  schedule:
    # Every Monday at 1:05am UTC
    - cron: '5 1 * * 1'

jobs:
  job-cleanup:
    runs-on: ubuntu-latest
    steps:
      - run: |
        curl -X "POST" "https://example.com/api/jobs/cleanup" \
          -H 'Content-Type: application/json; charset=utf-8' \
          -H 'Authorization: Bearer ${{ secrets.JOB_API_KEY }}' \
          -d $'{ "someKey": "someValue" }'

The workflow_dispatch above ensures that you can trigger (and easily test) the job manually from the GitHub Actions UI.


If you don't want to run a job via a URL, you can simply checkout your code, install dependencies and run a command, like:

name: Daily Cron

on:
  workflow_dispatch:
  schedule:
    # Daily, 1:15am UTC
    - cron: '15 1 * * *'

jobs:
  daily-cron:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - uses: actions/setup-node@v1
        with:
          node-version: 12.x
      - run: |
          make install
          make run/daily-cron
        env:
          SOME_ENV_VALUE: ${{ secrets.SOME_ENV_VALUE }}

NOTE: One important thing to note is that I still use EasyCron for very frequent web crons, because anything that runs more than once per hour can get expensive on GitHub (by default it'll just stop working once you reach the limits, but you can set a monthly limit/cap on GitHub Action minutes).

I hope you enjoy it.

Thank you so much for being here. I really appreciate you!