Skip to main content

Running one-off jobs

To run one-off jobs, we have the one-off jobs framework. All one-off jobs are defined in one-off-jobs.ts in the root of the repo: to add a new job:

  1. Add a new name for your job in the app/one-off-jobs/schema/one-off-jobs.ts schema file (idiomatically it should be named year-month-day-name, i.e. "2024-12-24-billing-promo-credits-backfill")
  2. Generate Drizzle migrations to include your new job name in the Postgres
  3. Run the Drizzle migrations
  4. Add your job definition in one-off-jobs.ts by calling defJob("name", { runInStaging: true }, async () => { /* ... */ }).

To test your job in dev, run:

npx tsx ./one-off-jobs.ts

Note that jobs will not re-run if they've completed once successfully (intentionally; they're one-offs!). If you need to re-run your job in development, just delete the row corresponding to it from the one_off_jobs table in your dev DB. They will re-run if they failed and didn't complete successfully: the DB write only happens once the job has finished without errors.

The options object's runInStaging is required: whether the job runs when the staging deploy runs it. Staging deploys before prod, so set it to false for jobs whose effects you don't want applied twice (sending emails, Stripe data (as Stripe is shared between staging and prod), ...). Staging has its own database, so skipping only skips the job for staging: it's still recorded as run there, and still runs when the deploy reaches prod.

Once you're finished writing your one-off job, make a PR and deploy it as usual. Kubernetes will run your job in staging and production as part of the deploy processes.

After your deploy succeeds, make a PR to delete your one-off job (don't delete the name from the enum; just the defJob call). The one-off job framework knows it already ran the job, so it doesn't need the code to stick around.