Berth

Workers and scheduled jobs

berth_hello_python has a worker and two cron jobs if you want to see both working.

Workers

Background processes go in the Procfile, next to the web process:

web: node server.js
worker: node worker.js
clock: node clock.js

Anything other than web and release is a worker. Each one runs as another process inside the app's container, with the same build, config and storage, and gets restarted (with backoff) if it exits. Workers move to each new release as it goes live, follow rollbacks, and stop and start with the app. The old release's workers stop before the new ones start, so a job never gets picked up twice. Each knows its name from BERTH_PROCESS (worker.2). You still need a web process, and it's always the image's own command: Berth doesn't read the web: line, so it's fine to keep it for other tools.

berth ps:scale myapp worker=3      # three of them
berth ps:scale myapp clock=0       # none
berth status myapp                 # each worker and how long it's been up
berth logs myapp -f                # worker lines say which: v4 worker.2: …

Workers share the app's memory and CPUs, so if they're heavy, give the app more with BERTH_MEMORY and BERTH_CPUS. The image needs /bin/sh, tr and grep, which every common base image has.

Scheduled jobs

Put a cron list in app.json at the root of the repo, in Dokku's format:

{
  "cron": [
    { "command": "node digest.js", "schedule": "0 7 * * *" },
    { "command": "python cleanup.py", "schedule": "@hourly" }
  ]
}

Schedules are ordinary five-field cron (minute hour day month weekday, with ranges, steps, lists and names like mon-fri) or @hourly, @daily, @weekly and @monthly, in the Mac's local time. They ship with the code, so a rollback brings back the schedule that went with it, and a typo fails the deploy rather than quietly never running.

Each run is a fresh container from the current release, with the app's config and storage. If a job is still running when its next turn comes round, that turn is skipped. When a job starts failing you get one notification, and another when it works again, not one per run (a job that runs every minute would otherwise send sixty an hour). BERTH_CRON_TIMEOUT (an hour by default) stops runaways. Runs missed while the Mac was off don't get made up.

berth cron myapp                   # the jobs, when they next run and how the last run went
berth cron:run myapp 1             # run job 1 now and wait for it
berth logs myapp --cron            # every run's output

Dev versions and previews don't run schedules. A job running against a copy of production's data could email real people. Try one by hand with berth cron:run myapp-dev 1.

Edit this page on GitHub (it's a section of the README)