diff --git a/scheduler.admin.inc b/scheduler.admin.inc
index 6b9b780..80143c3 100644
--- a/scheduler.admin.inc
+++ b/scheduler.admin.inc
@@ -170,69 +170,6 @@ function _scheduler_form_node_type_form_alter(array &$form, FormStateInterface $
 }
 
 /**
- * Form constructor for the lightweight cron form to allow a manual run.
- */
-function _scheduler_lightweight_cron(array $form, FormStateInterface $form_state) {
-  $form = array();
-  $form['scheduler_cron'] = array(
-    '#type' => 'submit',
-    '#prefix' => '<div class="container-inline">' . t("You can test Scheduler's lightweight cron process interactively") . ': ',
-    '#value' => t("Run Scheduler's lightweight cron now"),
-    '#submit' => array('_scheduler_lightweight_cron_submit'),
-    '#suffix' => "</div>\n",
-  );
-  $form['scheduler_cron_settings'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Lightweight cron settings'),
-  );
-  $form['scheduler_cron_settings']['scheduler_lightweight_log'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Log every activation and completion message.'),
-    '#default_value' => \Drupal::config('scheduler.settings')->get('log'),
-    '#description' => t("When this option is checked, Scheduler will write an entry to the dblog every time the lightweight cron process is started and completed. This is useful during set up and testing, but can result in a large number of log entries. Any actions performed during the lightweight cron run will always be logged regardless of this setting."),
-  );
-  $form['scheduler_cron_settings']['scheduler_lightweight_access_key'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Lightweight cron access key'),
-    '#size' => 100,
-    '#default_value' => \Drupal::config('scheduler.settings')->get('lightweight_cron_access_key'),
-    '#description' => t("Similar to Drupal's cron key this acts as a security token to prevent unauthorised calls to scheduler/cron. The key should be passed as scheduler/cron/&lt;this key&gt;. To disable security for lightweight cron leave this field blank."),
-  );
-  if (isset($form_state['scheduler_generate_new_key'])) {
-    $new_access_key = substr(md5(rand()), 0, 20);
-    $form_state['input']['scheduler_lightweight_cron_access_key'] = $new_access_key;
-    drupal_set_message(t('A new random key has been generated but not saved. If you wish to use this, first "Save Configuration" to store the value, then modify your crontab job.'), 'warning');
-  }
-  $form['scheduler_cron_settings']['create_key'] = array(
-    '#type' => 'submit',
-    '#value' => t('Generate new random key'),
-    '#submit' => array('_scheduler_generate_key'),
-  );
-  return system_settings_form($form);
-}
-
-/**
- * Form submission handler for _scheduler_lightweight_cron().
- */
-function _scheduler_lightweight_cron_submit() {
-  // Load the cron functions file.
-  module_load_include('inc', 'scheduler', 'scheduler.cron');
-  _scheduler_run_cron();
-}
-
-/**
- * Form submission handler for _scheduler_lightweight_cron().
- *
- * This only fires when the 'Generate new random key' button is clicked.
- */
-function _scheduler_generate_key(array $form, FormStateInterface $form_state) {
-  // Everything in $form_state is persistent, so we can use a direct attribute.
-  $form_state['scheduler_generate_new_key'] = TRUE;
-  // Setting $form_state['rebuild'] = TRUE causes the form to be rebuilt again.
-  $form_state['rebuild'] = TRUE;
-}
-
-/**
  * Page callback: Generate the timecheck admin page.
  */
 function _scheduler_timecheck() {
diff --git a/scheduler.cron.inc b/scheduler.cron.inc
index 799769c..925e4a6 100644
--- a/scheduler.cron.inc
+++ b/scheduler.cron.inc
@@ -1,7 +1,5 @@
 <?php
 
-use Drupal\node\Entity\Node;
-
 /**
  * @file
  * Scheduler cron functions.
@@ -9,7 +7,9 @@ use Drupal\node\Entity\Node;
  * This file is included only when running a crontab job or executing the
  * lightweight cron via the admin interface.
  */
+
 use Drupal\Core\Url;
+use Drupal\node\Entity\Node;
 
 /**
  * Publish scheduled nodes.
@@ -25,7 +25,8 @@ function _scheduler_publish() {
   $query = db_select('scheduler', 's');
   $query->addField('s', 'nid');
   $query->addJoin('INNER', 'node', 'n', 's.nid = n.nid');
-  $query->addJoin('INNER', 'users', 'u', 'u.uid = n.uid');
+  $query->addJoin('LEFT', 'node_field_data', 'nd', 'n.nid = nd.nid');
+  $query->addJoin('INNER', 'users', 'u', 'u.uid = nd.uid');
   $query->condition('s.publish_on', 0, '>');
   $query->condition('s.publish_on', REQUEST_TIME, '<=');
   $query_result = $query->execute();
@@ -114,7 +115,8 @@ function _scheduler_unpublish() {
   $query = db_select('scheduler', 's');
   $query->addField('s', 'nid');
   $query->addJoin('INNER', 'node', 'n', 's.nid = n.nid');
-  $query->addJoin('INNER', 'users', 'u', 'u.uid = n.uid');
+  $query->addJoin('LEFT', 'node_field_data', 'nd', 'n.nid = nd.nid');
+  $query->addJoin('INNER', 'users', 'u', 'u.uid = nd.uid');
   $query->condition('s.unpublish_on', 0, '>');
   $query->condition('s.unpublish_on', REQUEST_TIME, '<=');
   $query_result = $query->execute();
@@ -238,14 +240,6 @@ function _scheduler_run_cron() {
     }
   }
   if ($log) {
-    \Drupal::logger('scheduler')->notice('Lightweight cron run completed.', array('link' => l(t('settings'), 'admin/config/content/scheduler/cron')));
-  }
-
-  if (\Drupal::request()->getRequestUri() === 'admin/config/content/scheduler/cron') {
-    // This cron run has been initiated manually from the configuration form.
-    // Give a message and return something so that an output page is created.
-    // No output should be returned if running from a crontab job.
-    drupal_set_message(t('Lightweight cron run completed - see <a href="@url">log</a> for details.', array('@url' => Url::fromRoute('dblog.overview'))));
-    return ' ';
+    \Drupal::logger('scheduler')->notice('Lightweight cron run completed.', array('link' => Drupal::l(t('settings'), Url::fromRoute('scheduler.cron_form'))));
   }
 }
diff --git a/scheduler.links.task.yml b/scheduler.links.task.yml
index 82b587c..7e11d4c 100644
--- a/scheduler.links.task.yml
+++ b/scheduler.links.task.yml
@@ -1,5 +1,11 @@
-scheduler.admin_form:
+scheduler.settings_tab:
   route_name: scheduler.admin_form
   title: Settings
   weight: 5
   base_route: scheduler.admin_form
+
+scheduler.cron_tab:
+  route_name: scheduler.cron_form
+  title: Lightweight Cron
+  weight: 10
+  base_route: scheduler.admin_form
diff --git a/scheduler.module b/scheduler.module
index dc4e966..c9b7008 100644
--- a/scheduler.module
+++ b/scheduler.module
@@ -55,16 +55,6 @@ function scheduler_menu() {
     'type' => MENU_DEFAULT_LOCAL_TASK,
     'weight' => 5,
   );
-  $items['admin/config/content/scheduler/cron'] = array(
-    'title' => 'Lightweight Cron',
-    'description' => 'A lightweight cron handler to allow more frequent runs of Schedulers internal cron system.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('_scheduler_lightweight_cron'),
-    'access arguments' => array('administer scheduler'),
-    'type' => MENU_LOCAL_TASK,
-    'weight' => 10,
-    'file' => 'scheduler.admin.inc',
-  );
   $items['admin/config/content/scheduler/timecheck'] = array(
     'title' => 'Time Check',
     'description' => 'Allows site admin to check their servers internal clock',
diff --git a/scheduler.routing.yml b/scheduler.routing.yml
index 6e8053d..1a8d2da 100644
--- a/scheduler.routing.yml
+++ b/scheduler.routing.yml
@@ -5,3 +5,12 @@ scheduler.admin_form:
     _form: \Drupal\scheduler\Form\SchedulerAdminForm
   requirements:
     _permission: 'administer scheduler'
+
+scheduler.cron_form:
+  path: /admin/config/content/scheduler/cron
+  defaults:
+    _title: Lightweight Cron
+    _description: A lightweight cron handler to allow more frequent runs of Schedulers internal cron system.
+    _form: \Drupal\scheduler\Form\SchedulerCronForm
+  requirements:
+    _permission: 'administer scheduler'
diff --git a/src/Form/SchedulerCronForm.php b/src/Form/SchedulerCronForm.php
new file mode 100644
index 0000000..ec86926
--- /dev/null
+++ b/src/Form/SchedulerCronForm.php
@@ -0,0 +1,140 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\scheduler\Form\SchedulerCronForm.
+ */
+
+namespace Drupal\scheduler\Form;
+
+use Drupal\Core\Form\ConfigFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+use Drupal\Core\Url;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
+
+/**
+ * Scheduler Lightweight Cron form.
+ */
+class SchedulerCronForm extends ConfigFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'scheduler_cron_form';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['scheduler.settings'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $config = $this->config('scheduler.settings');
+
+    $form['cron_settings'] = [
+      '#type' => 'fieldset',
+      '#title' => $this->t('Lightweight cron settings'),
+    ];
+    $form['cron_settings']['lightweight_log'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Log every activation and completion message.'),
+      '#default_value' => $config->get('log'),
+      '#description' => $this->t('When this option is checked, Scheduler will write an entry to the dblog every time the lightweight cron process is started and completed. This is useful during set up and testing, but can result in a large number of log entries. Any actions performed during the lightweight cron run will always be logged regardless of this setting.'),
+    ];
+    $form['cron_settings']['lightweight_access_key'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Lightweight cron access key'),
+      '#default_value' => $config->get('lightweight_cron_access_key'),
+      '#size' => 25,
+      '#description' => $this->t("Similar to Drupal's cron key this acts as a security token to prevent unauthorised calls to scheduler/cron. The key should be passed as scheduler/cron/&lt;this key&gt;. To disable security for lightweight cron leave this field blank."),
+    ];
+    // Add a submit handler function for the key generation.
+    $form['cron_settings']['create_key'][] = [
+      '#type' => 'submit',
+      '#value' => $this->t('Generate new random key'),
+      '#submit' => ['::generateRandomKey'],
+      // No validation at all is required in the equivocate case, so
+      // we include this here to make it skip the form-level validator.
+      '#validate' => array(),
+    ];
+    // Add a submit handler function for the form.
+    $form['buttons']['submit_cron'][] = [
+      '#type' => 'submit',
+      '#prefix' => '<div class="container-inline">' . $this->t("You can test Scheduler's lightweight cron process interactively") . ': ',
+      '#value' => $this->t("Run Scheduler's lightweight cron now"),
+      '#suffix' => "</div>\n",
+      '#submit' => ['::runLightweightCron'],
+      // No validation at all is required in the equivocate case, so
+      // we include this here to make it skip the form-level validator.
+      '#validate' => array(),
+    ];
+    return parent::buildForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $config = $this->config('scheduler.settings');
+    $config->set('log', $form_state->getValue('lightweight_log'));
+    $config->set('lightweight_cron_access_key', $form_state->getValue('lightweight_access_key'));
+    $config->save();
+    parent::submitForm($form, $form_state);
+  }
+
+  /**
+   * Form submission handler for the random key generation.
+   *
+   * This only fires when the 'Generate new random key' button is clicked.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   */
+  public function generateRandomKey(array &$form, FormStateInterface $form_state) {
+    $config = $this->config('scheduler.settings');
+    $config->set('lightweight_cron_access_key', substr(md5(rand()), 0, 20));
+    $config->save();
+    parent::submitForm($form, $form_state);
+  }
+
+  /**
+   * Form submission handler to run the lightweight cron.
+   *
+   * This only fires when "Run Scheduler's lightweight cron now" is clicked.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   */
+  public function runLightweightCron(array &$form, FormStateInterface $form_state) {
+    module_load_include('inc', 'scheduler', 'scheduler.cron');
+    _scheduler_run_cron();
+
+    $message = $this->t('Lightweight cron run completed.');
+
+    // Only show a link to the log overview if the Database Logging module is
+    // enabled.
+    try {
+      $url = Url::fromRoute('dblog.overview')->toString();
+      $message = $this->t('Lightweight cron run completed. See the <a href="@url">log</a> for details.', array('@url' => $url));
+    }
+    catch (RouteNotFoundException $e) {
+      // If the module is not enabled the route does not exist and the original
+      // message will be used.
+    }
+    // @todo Replace drupal_set_message() with an injectable service in 8.1.x.
+    // @see https://www.drupal.org/node/2278383
+    drupal_set_message($message);
+  }
+
+}
