Deployment
Jobber is written in Go, and it should be possible to compile and run it on any Unix/Linux system.
Installation from a Package
The easiest way to install Jobber is via a binary package.
Compilation and Installation from Source
Instead of installing a binary package, you can certainly compile and install Jobber yourself.
You need Go 1.8 or later to compile Jobber. So, install Go, pick a
place for your workspace (say, /path/to/your/workspace), and ensure that the
environment variable GOPATH
includes a path to your workspace.
Then:
cd /path/to/your/workspace mkdir -p src/github.com/dshearer cd src/github.com/dshearer git clone https://github.com/dshearer/jobber.git cd jobber git checkout v1.3.3 make check sudo make install DESTDIR=/
This will install the following:
- /usr/local/bin/jobber
- /usr/local/libexec/jobbermaster
- /usr/local/libexec/jobberrunner
Finally, do something to ensure that jobbermaster runs as a daemon (as root) when your computer boots. Note that jobbermaster does not daemonize itself, but that should not be a problem if you use systemd; otherwise, daemonize(1) could help.
Putting Jobber to Work
As with cron, each user can have its own set of jobs, which will be run under that user’s privileges. A user’s jobs are defined in a jobfile — a file named “.jobber” in the user’s home directory.
IMPORTANT: Jobfiles must be owned by the user who owns the home directory that contains them, and their permissions must not allow the owning group or any other users to write to them (i.e., the permission bits must exclude 022).
Here's an example that defines two jobs:
[prefs] notifyProgram: /home/foobar/handleError.sh [jobs] - name: DailyBackup cmd: backup daily time: 0 0 13 onError: Stop notifyOnError: true notifyOnFailure: false - name: OffsiteBackup cmd: | mount /backup/offsite mount /backup/linux/weekly backup-offsite /backup/linux/weekly/backup-0 linux || exit 1 umount /backup/linux/weekly umount /backup/offsite time: 0 0 14 * * 1 onError: Stop
As shown, there are two sections:
prefs
and
jobs
. The contents of both sections are YAML
documents.
Time Strings
Field
time
specifies the schedule at which a job is run, in a manner similar to how
cron jobs’ schedules are specified: with a space-separated list of up
to six specifiers, each one of which constrains a different component of
time (second, minute, hour, etc.). Schematically:
sec min hour month_day month week_day
A job is scheduled thus: the next run time is the time that satisfies the second, minute, hour, and month specifiers and at least one of the month-day and weekday specifiers.
Important: If a specifier is one of the random specifiers
(beginning with
R
), a random value is chosen when the jobfile is loaded, and stays the same
until the jobfile is loaded again.
Each specifier can take one of the following forms: (“a”, “b”, “c”, and “n” are placeholders for arbitrary numerals.)
Specifier Form | What It Matches |
---|---|
* |
Any value |
a
|
The value a |
*/n |
Every a-th value — e.g., */25 in
the second specifier would match 0, 25, and 50, whereas in the month
specifier it would match 1 and 26.
|
a,b,c,... |
The values a, b, c, ...
— e.g., 10, 20, 30, 40 matches 10, 20, 30, and 40.
|
a-b |
Any of the values between and including a and b |
R
| A random value |
Ra-b
| A random value between and including a and b |
The specifiers have different permitted values for the placeholders in the specifier forms:
Specifier | Values for “a”, “b”, and “c” | Values for “n” |
---|---|---|
sec | 0 thru 59 |
1 thru 59 |
min | 0 thru 59 |
1 thru 59 |
hour | 0 thru 23 |
1 thru 23 |
month_day | 1 thru 31 |
1 thru 30 |
month | 1 thru 12 |
1 thru 11 |
week_day | 0 (Sunday) thru 6 (Saturday) |
1 thru 5 |
The default value for
time
is
* * * * * *
.
Error-handling
When a job (or, specifically, the shell code that the job runs) exited with a non-0 status, we call this a “job error”.
One of Jobber’s main features is that you can control how Jobber handles job
errors. You do this by setting the
onError
field in a job’s definition to one of these values:
Value | Effect when a job error happens |
---|---|
Stop |
Stop scheduling runs of this job. |
Backoff |
Schedule runs of this job according to an exponential backoff algorithm. If a later run of the job succeeds, jobber resumes scheduling this job normally; but if the job continues to err, Jobber will eventually stop scheduling it. |
Continue |
Continue scheduling this job normally. |
When Jobber stops scheduling runs of a job due to one or more job errors, we call this a “job failure”.
If you would like Jobber to notify you when a job error or job failure occurs, do the following:
- Write a notify program that does whatever you want done after a job error or job failure
- Set the
notifyProgram
field in theprefs
section of the Jobber file to the path to your notify program
The input that Jobber will send to the notify program is described elsewhere.
Job Status Notifications
You can arrange for Jobber to send notifications when certain events happen for a particular job:
Job success | The job (or, specifically, the shell script that the job runs) exited with status 0 |
Job error | The job (or, specifically, the shell script that the job runs) exited with a non-0 status |
Job failure | Jobber stopped scheduling runs of the job due to one or more job errors |
By default, these notifications consist of emails to the user account that owns the job. Jobber uses sendmail to do this.
Also, by default, Jobber will send notifications when any job fails. To
disable this for a particular job, set
notifyOnFailure
in that job’s definition to
false
.
To enable notifications when a particular job succeeds, set
notifyOnSuccess
to
true
in that job’s definition.
To enable notifications when a particular job errs, set
notifyOnError
to
true
in that job’s definition.
For example, in the following, for DailyBackup Jobber will send notifications only on job error, while for OffsiteBackup it will send notifications only on job failure:
[prefs] ... [jobs] - name: DailyBackup notifyOnError: true notifyOnFailure: false ... - name: OffsiteBackup onError: Stop ...
Notify Programs
Rather than having Jobber notify by sending emails, you can have it call an arbitrary program, called a “notify program”.
To do so, in the
prefs
section of your jobfile define
notifyProgram
to be a path to your notify program, thus:
[prefs] notifyProgram: /home/dylan/myNotifyProgram.sh
(Make sure the notify program is executable.)
When Jobber calls your notify program, it will write to stdin a JSON document like this:
{ "job":{ "command":"/home/dylan/some_program", "name":"MyHourlyJob", "notifyOnError":true, "notifyOnFailure":false, "onError":"Stop", "status":"Failed", "time":"0 0 * * * *" }, "startTime":"May 29 15:25:10 2017", "stderr":"Some errors\n", "stderr_base64":false, "stdout":"Quotes: \"adf\"\n", "stdout_base64":false, "succeeded":false, "user":"dylan" }
The fields in the
job
object are from the job’s definition, except for
status
, which indicates whether and how Jobber will
schedule runs of the job in the future. Its possible values
are
Good
,
Backoff
, or
Failed
.
stdout
(respectively,
stderr
) contains whatever the job wrote to stdout (stderr). If
stdout_base64
(stderr_base64
)
contains
false
, then the job wrote only UTF-8 bytes to stdout (stderr), and
stdout
(
stderr
) contains a string with those bytes; otherwise, there were some non-UTF-8
bytes and
stdout
(
stderr
) contains a Base64 encoding of the output.
Keeping a Log of Job Runs
The jobber log
command prints the run log — i.e., a log
containing info about previous runs. By default, the run log only contains the 100 most recent
runs, and it is not written to disk, which means that it will be lost when the Jobber service stops
or restarts.
Here is an example of keeping the run log in memory:
[prefs] runLog: type: memory maxLen: 500
With this, Jobber will keep log entries for no more than the 500 most recent runs of any of the user’s jobs.
Here is an example of keeping the run log on disk:
[prefs] runLog: type: file path: /var/log/jobber-runs maxFileLen: 100m maxHistories: 2
With this, Jobber will write run log entries to /var/log/jobber-runs. /var/log/jobber-runs will grow to no more than 100 MB, and Jobber will rotate it when it gets too big. Jobber will keep up to two of these rotated “history” files (named “jobber-runs.1” and “jobber-runs.2”). When it is necessary to delete a history file, the oldest one will get the axe.
Loading Jobs
After you've created a user’s jobfile, log in as that user and do:
jobber reload
You can also reload all users’ jobfiles by logging in as root and doing:
jobber reload -a
Listing Jobs
You can list the jobs for a particular user by logging in as that user and doing
jobber list
This command also shows you the status of each job — that is, whether the job is being scheduled as normal, the exponential backoff algorithm is being applied, or the job has failed.
As with the
reload
command, you can do the same for all users by adding the
-a
option as root.
Listing Runs
You can see a list of recent runs of any jobs for a particular user by logging in as that user and doing
jobber log
As with the other commands, you can do the same for all users by adding the
-a
option as root.
Testing Jobs
If you'd like to test out a job, do
jobber test JOB_NAME
Jobber will immediately run that job, tell you whether it succeeded, and show you its output.
Pausing and Resuming Jobs
You can temporarily stop Jobber from running a job thus:
jobber pause JOB_NAME
And of course you can resume it:
jobber resume JOB_NAME
NOTE: If a job is paused when the Jobber service stops, then when the Jobber service starts again the job will be scheduled normally.
Printing a Job’s Command
You can print a job’s command (the shell script that it executes) thus:
jobber cat JOB_NAME