Jobba the Hub, a job scheduler and runner.
Jobba is a wrapper around Bull, which makes it a lot easier to work with (at least for our uses). It is written in TypeScript and used internally by Whitebox. It has an exposed HTTP API built upon Yawk, a great HTTP router and server. It also serves a simple management interface, (our fork of) Arena.
Jobba
: The job hub itself, which is what you register and scheduleTask
s with.Jobba#register
returns aTask
.
Task
: Handlers that you register, which can be scheduled to run (creating aJob
).Task#schedule
schedules the run of aTask
.- Upon run, a
Job
is created and passed to theTask
's handler.
Job
: A scheduledTask
, which can be a one-off run of its handler or a recurring run.
import Jobba, { Job, JobbaConfig } from 'jobba';
const config: JobbaConfig = {
yawk: {
port: 5000
}
};
function registrar(jobba: Jobba) {
jobba.register({
id: 'some-task',
handler: async (job: Job) => {
await job.log('The params passed to this job:', job.params);
return 'some response';
}
});
}
const jobba = new Jobba(config, registrar);
jobba.start();
NOTE: The
Job
andJobbaConfig
type annotations are not needed, but are shown for clarity.
There are three ways to interact with Jobba:
- the Node.js module
- the HTTP API
- the front-end
// one-off run
jobba.schedule('some-task', { some: 'params' });
// recurring run
jobba.schedule('some-task', { some: 'params' }, {
repeat: { cron: '0 * * * *' }
});
The API is served at /api
.
GET /api/routes
returns a list of endpoints and in some cases their descriptions or expected input and output schemas.
The most important endpoint is POST /api/tasks/${taskId}/schedule
, which supports passing optional params
and options
like in this example:
{
"options": {
"repeat": {
"cron": "0 * * * *"
}
},
"params": {
"some": "params"
}
}
The front-end is served at /
.
In its current state it is quite simplistic, and is mostly read-only for now.
You cannot yet schedule tasks, though you can see details about completed/failed tasks as well as cancel scheduled ones.
Tasks do not need to return anything. Their return values are indeed reflected in the front-end, but in practice most of our tasks don't return anything.
Any errors thrown are captured and reflected in the front-end as well, with their error message and stack trace.
jobba.register({
id: 'some-task',
handler: (job: Job) => {
throw new Error('uh oh...');
}
});
Logs are recorded with their log level, a timestamp, and their contents.
jobba.register({
id: 'some-task',
handler: async (job: Job) => {
await job.log('Logging can be convenient.');
await job.info('Logging can be informative.');
await job.debug('Logging can be introspective.');
await job.warn('Logging can be dangerous.');
await job.error('Logging can be unfortunate.');
await job.log('logs', 'support', 'infinite', 'arguments');
await job.log('logs', 'support', [ 'various' ], { types: true });
}
});
export class MyCustomJob extends Job {
public async init(): Promise<any> {
// Code here executed before the job's `process` function is invoked.
}
public async process(): Promise<any> {
// Do some processing work...
}
public async onProcessCompleted(): Promise<any> {
// The `process` function has completed.
// Can use this function for cleanup, logging, etc.
}
}
jobba.register({
id: 'some-task',
handler: async (job: Job) => {
// you can set progress
await job.progress(40)
}
});