Skip to content

whitebox-co/jobba

Repository files navigation

Jobba

Jobba the Hub, a job scheduler and runner.

Description

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.

Terminology

  • Jobba: The job hub itself, which is what you register and schedule Tasks with.
    • Jobba#register returns a Task.
  • Task: Handlers that you register, which can be scheduled to run (creating a Job).
    • Task#schedule schedules the run of a Task.
    • Upon run, a Job is created and passed to the Task's handler.
  • Job: A scheduled Task, which can be a one-off run of its handler or a recurring run.

Usage

Setup

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 and JobbaConfig type annotations are not needed, but are shown for clarity.

There are three ways to interact with Jobba:

  1. the Node.js module
  2. the HTTP API
  3. the front-end

Module

// one-off run
jobba.schedule('some-task', { some: 'params' });

// recurring run
jobba.schedule('some-task', { some: 'params' }, {
	repeat: { cron: '0 * * * *' }
});

HTTP API

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"
	}
}

Front-end

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.

Features

Returns

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.

Errors

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...');
	}
});

Logging

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 });
	}
});

Creating a Job subclass

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.
	}

}

Misc

jobba.register({
	id: 'some-task',
	handler: async (job: Job) => {
		// you can set progress
		await job.progress(40)
	}
});

Releases

No releases published

Packages

No packages published