function processJob(token, plugins, manager) {
  return (
    // jobStart
    runLifecycle('jobStart', plugins, manager, token)

      .then(() => {
        // beforeRender
        runLifecycleSync('beforeRender', plugins, manager, token);

        // render
        return manager.render(token);
      })
      // jobEnd
      .then(() => {
        // afterRender
        runLifecycleSync('afterRender', plugins, manager, token);

        return runLifecycle('jobEnd', plugins, manager, token);
      })
      .catch((err) => {
        manager.recordError(err, token);
        errorSync(err, plugins, manager, token);
      })
  );
}
Runs through the job-level lifecycle events of the job based on the provided token. This includes
the actual rendering of the job.

Returns a promise resolving when the job completes.

@param {String} token
@param {Array<HypernovaPlugin>} plugins
@param {BatchManager} manager
@returns {Promise}