Cron jobs are useful for setting up automated tasks that run periodically. While several services offer cron job functionality, they often have limitations.
For instance, Vercel's Cron Job in its free tier offers:
- 2 cron jobs total, each triggered once per day
- 10 seconds maximum duration for each cron job
This 10-second limit can be restrictive. During my work on Repohistory, I needed a cron job to fetch users' repo traffic data daily. As the user base grew, completing this task within 10 seconds became unfeasible.
That's why I explored an alternative solution for cron jobs.
GitHub Action
GitHub Actions is a CI/CD platform that allows you to execute workflows triggered by any GitHub events. This feature is particularly useful for tasks like building and deploying your website following a new commit.
A workflow in GitHub Actions is an automated process defined in YAML. These workflows are stored in the .github/workflows
directory of your repository and follow a specific structure.
Here's an example of a workflow file that prints the content of hello_world.txt
when a new commit is pushed to the repository:
name: hello-world
on: push
jobs:
hello-world-job:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
- run: echo "$(cat hello_world.txt)"
You can learn more about the detail on GitHub Resources.
The key part of a workflow is the on
, which specifies the GitHub events that will activate the workflow. In the above example, the event is push
, meaning the workflow runs on any commit push.
An additional event type is schedule
, which is ideal for cron jobs.
Cron job on GitHub Action
The schedule
event allows workflows to run at scheduled times, defined using cron syntax. For example, this configuration triggers a workflow every day at 5:30 AM and 5:30 PM:
on:
schedule:
- cron: '30 5,17 * * *'
The limits for GitHub Actions are generous:
- 20 concurrent jobs
- 6 hours maximum duration per job
These limits are typically more than sufficient for most tasks.
A practical example
For Repohistory, I implemented a GitHub Action to run a cron job. The src/cron.ts
script fetches and saves users' repo traffic data to a database. To keep the data up to date, it runs three times a day:
// src/cron.ts
import updateTraffic from './services/updateTraffic';
import { app } from './utils/octokit';
app.eachInstallation(({ installation }) => {
updateTraffic(installation.id);
});
Let's go through the workflow file step by step. I first set the cron to '0 */8 * * *'
so the workflow runs 3 times everyday ( on 00:00, 08:00, 16:00 ):
name: Cron Job
on:
schedule:
- cron: '0 */8 * * *'
This workflow only has one job that is executing src/cron.ts
, so the first few steps is to check out the repo and set up Node.js:
jobs:
execute-script:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
Then install the dependencies of my project:
- name: Install dependencies
run: npm install
Finally compiles the TypeScript file and then execute it. Because the job use GitHub and Supabase API so I also pass some environment variables into it:
- name: Compile TypeScript file
run: npx tsc src/cron.ts --outDir dist
- name: Run the compiled script
env:
NEXT_PUBLIC_APP_ID: ${{ secrets.NEXT_PUBLIC_APP_ID }}
NEXT_PUBLIC_PRIVATE_KEY: ${{ secrets.NEXT_PUBLIC_PRIVATE_KEY }}
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
run: node dist/cron.js
You can see the complete workflow file here.
That's pretty much about how I run free cron job on GitHub Action when building Repohistory! Feel free to check this project out on GitHub!
Top comments (0)