diff --git a/config/schema/ultimate_cron.schema.yml b/config/schema/ultimate_cron.schema.yml
index a14a92f..9a69a4d 100644
--- a/config/schema/ultimate_cron.schema.yml
+++ b/config/schema/ultimate_cron.schema.yml
@@ -113,7 +113,6 @@ ultimate_cron.settings:
               type: string
               label: Rule for Simple scheduler
 
-# @todo make schema pluggable
 ultimate_cron.job.*:
   type: config_entity
   label: 'Cron Job'
@@ -124,6 +123,9 @@ ultimate_cron.job.*:
     id:
       type: string
       label: 'Machine-readable name'
+    weight:
+      type: integer
+      label: 'Weight'
     module:
       type: string
       label: 'Module Name'
diff --git a/src/CronJobDiscovery.php b/src/CronJobDiscovery.php
index fe2cde1..63c42ba 100644
--- a/src/CronJobDiscovery.php
+++ b/src/CronJobDiscovery.php
@@ -1,13 +1,9 @@
 <?php
-/**
- * @file
- * Contains \Drupal\ultimate_cron\CronJobDiscovery.
- *
- * Cron Job helper class.
- */
+
 namespace Drupal\ultimate_cron;
 
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Queue\QueueWorkerManagerInterface;
 use Drupal\ultimate_cron\Entity\CronJob;
 
 /**
@@ -21,22 +17,59 @@ class CronJobDiscovery {
   protected $moduleHandler;
 
   /**
+   * @var \Drupal\Core\Queue\QueueWorkerManagerInterface
+   */
+  protected $queueManager;
+
+  /**
    * CronJobDiscovery constructor.
    *
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
+   * @param \Drupal\Core\Queue\QueueWorkerManagerInterface $queue_manager
+   *   The queue manager.
    */
-  public function __construct(ModuleHandlerInterface $module_handler) {
+  public function __construct(ModuleHandlerInterface $module_handler, QueueWorkerManagerInterface $queue_manager) {
     $this->moduleHandler = $module_handler;
+    $this->queueManager = $queue_manager;
   }
 
   /**
    * Automatically discovers and creates default cron jobs.
    */
   public function discoverCronJobs() {
+    // Create cron jobs for hook_cron() implementations.
     foreach ($this->getHooks() as $id => $info) {
       $this->ensureCronJobExists($info, $id);
     }
+
+    // Create cron jobs for queue plugins.
+    foreach ($this->queueManager->getDefinitions() as $id => $definition) {
+      if (!isset($definition['cron'])) {
+        continue;
+      }
+
+      $job_id = CronJobInterface::QUEUE_ID_PREFIX . $id;
+      if (!CronJob::load($job_id)) {
+        $values = [
+          'title' => t('Queue: @title', ['@title' => $definition['title']]),
+          'id' => $job_id,
+          'module' => $definition['provider'],
+          // Process queue jobs later by default.
+          'weight' => 10,
+          'callback' => 'ultimate_cron_queue_callback',
+          'scheduler' => [
+            'id' => 'simple',
+            'configuration' => [
+              'rules' => ['* * * * *'],
+            ],
+          ]
+        ];
+
+        $job = CronJob::create($values);
+        $job->save();
+      }
+    }
   }
 
   /**
diff --git a/src/CronJobInterface.php b/src/CronJobInterface.php
index 0c2142e..4a49227 100644
--- a/src/CronJobInterface.php
+++ b/src/CronJobInterface.php
@@ -13,6 +13,11 @@ use Drupal\ultimate_cron\Logger\LoggerBase;
 interface CronJobInterface extends ConfigEntityInterface {
 
   /**
+   * Cron job ID prefix for queue jobs.
+   */
+  const QUEUE_ID_PREFIX = 'ultimate_cron_queue_';
+
+  /**
    * Get locked state for multiple jobs.
    *
    * @param array $jobs
diff --git a/src/CronJobListBuilder.php b/src/CronJobListBuilder.php
index a5184d6..4f172b5 100644
--- a/src/CronJobListBuilder.php
+++ b/src/CronJobListBuilder.php
@@ -7,8 +7,7 @@
 
 namespace Drupal\ultimate_cron;
 
-use Drupal\Component\Render\FormattableMarkup;
-use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
+use Drupal\Core\Config\Entity\DraggableListBuilder;
 use Drupal\Core\Entity\EntityInterface;
 
 /**
@@ -16,15 +15,19 @@ use Drupal\Core\Entity\EntityInterface;
  *
  * @see \Drupal\ultimate_cron\Entity\CronJob
  */
-class CronJobListBuilder extends ConfigEntityListBuilder {
+class CronJobListBuilder extends DraggableListBuilder {
+
+  public function getFormId() {
+    return 'ultimate_cron_job_list';
+  }
 
   /**
    * {@inheritdoc}
    */
   public function buildHeader() {
     $header = array();
+    $header['label'] = array('data' => t('Title'));
     $header['module'] = array('data' => t('Module'));
-    $header['title'] = array('data' => t('Title'));
     $header['scheduled'] = array('data' => t('Scheduled'));
     $header['started'] = array('data' => t('Last Run'));
     $header['duration'] = array('data' => t('Duration'));
@@ -40,34 +43,31 @@ class CronJobListBuilder extends ConfigEntityListBuilder {
     $behind_icon = ['#prefix' => ' ', '#theme' => 'image', '#uri' => file_create_url($icon), '#title' => t('Job is behind schedule!')];
 
     $log_entry = $entity->loadLatestLogEntry();
-    $row['module'] = array(
-      'data' => $entity->getModuleName(),
-      'title' => strip_tags($entity->getModuleDescription()),
-    );
-    $row['title'] = $entity->label();
-    $row['scheduled']['data']['label']['#markup'] = $entity->getPlugin('scheduler')->formatLabel($entity);
+    $row['label'] = $entity->label();
+    $row['module']['#markup'] = $entity->getModuleName();
+    $row['status']['#wrapper_attributes']['title'] = $entity->getModuleDescription();
+    $row['scheduled']['label']['#markup'] = $entity->getPlugin('scheduler')->formatLabel($entity);
     if ($entity->isScheduled()) {
-      $row['scheduled']['data']['behind'] = $behind_icon;
+      $row['scheduled']['behind'] = $behind_icon;
     }
     else {
       $row['scheduled'] = $entity->getPlugin('scheduler')->formatLabel($entity);
     }
     // If the start time is 0, the jobs have never been run.
-    $row['started'] = $log_entry->start_time ? \Drupal::service('date.formatter')->format($log_entry->start_time, "short") : $this->t('Never');
+    $row['started']['#markup'] = $log_entry->start_time ? \Drupal::service('date.formatter')->format($log_entry->start_time, "short") : $this->t('Never');
 
     // Display duration
     $progress = $entity->isLocked() ? $entity->formatProgress() : '';
-    $row['duration'] = array(
-      'data' => ['#markup' => '<span class="duration-time" data-src="' . $log_entry->getDuration() . '">' . $log_entry->formatDuration() . '</span> <span class="duration-progress">' . $progress . '</span>'],
-      'class' => array('ctools-export-ui-duration'),
-      'title' => strip_tags($log_entry->formatEndTime()),
-    );
+    $row['duration'] = [
+      '#markup' => '<span class="duration-time" data-src="' . $log_entry->getDuration() . '">' . $log_entry->formatDuration() . '</span> <span class="duration-progress">' . $progress . '</span>',
+      '#wrapper_attributes' => ['title' => $log_entry->formatEndTime()],
+     ];
 
     if (!$entity->isValid()) {
-      $row['status'] = $this->t('Missing');
+      $row['status']['#markup'] = $this->t('Missing');
     }
     elseif (!$entity->status()) {
-      $row['status'] = $this->t('Disabled');
+      $row['status']['#markup'] = $this->t('Disabled');
     }
     else {
       // Get the status from the launcher when running, otherwise use the last
@@ -83,14 +83,13 @@ class CronJobListBuilder extends ConfigEntityListBuilder {
         $title = $log_entry->message ? $log_entry->message : $title;
       }
 
-      $row['status'] = [
-        'data' => $status,
-        'class' => array('ctools-export-ui-status'),
-        'title' => strip_tags($title),
-      ];
+      $row['status'] = $status;
+      $row['status']['#wrapper_attributes']['title'] = $title;
     }
 
-    return $row + parent::buildRow($entity);
+    $row += parent::buildRow($entity);
+    $row['weight']['#delta'] = 50;
+    return $row;
   }
 
   /**
diff --git a/src/Entity/CronJob.php b/src/Entity/CronJob.php
index 09db8ac..9e3220f 100644
--- a/src/Entity/CronJob.php
+++ b/src/Entity/CronJob.php
@@ -39,11 +39,13 @@ use Exception;
  *     "id" = "id",
  *     "label" = "title",
  *     "status" = "status",
+ *     "weight" = "weight",
  *   },
  *   config_export = {
  *     "title",
  *     "id",
  *     "status",
+ *     "weight",
  *     "module",
  *     "callback",
  *     "scheduler",
@@ -84,6 +86,13 @@ class CronJob extends ConfigEntityBase implements CronJobInterface {
   protected $status = TRUE;
 
   /**
+   * The weight.
+   *
+   * @var int
+   */
+  protected $weight = 0;
+
+  /**
    * @var string
    */
   protected $title;
@@ -287,7 +296,7 @@ class CronJob extends ConfigEntityBase implements CronJobInterface {
       CronPlugin::hook_cron_pre_invoke($this);
       \Drupal::moduleHandler()->invokeAll('cron_pre_invoke', array($this));
 
-      $callback = $this->callback;
+      $callback = $this->getCallback();
       $result = $callback($this->id());
 
     } catch (Exception $e) {
diff --git a/src/QueueSettings.php b/src/QueueSettings.php
deleted file mode 100644
index 4440872..0000000
--- a/src/QueueSettings.php
+++ /dev/null
@@ -1,384 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\ultimate_cron\QueueSettings.
- *
- * Queue settings for Ultimate Cron.
- */
-
-namespace Drupal\ultimate_cron;
-
-use Drupal\Core\Logger\RfcLogLevel;
-use Drupal\ultimate_cron\Entity\CronJob;
-use Drupal\ultimate_cron\TaggedSettings;
-
-/**
- * Queue settings plugin class.
- */
-class QueueSettings extends TaggedSettings {
-  static private $throttled = array();
-  static private $queues = NULL;
-
-  /**
-   * Get cron queues and static cache them.
-   *
-   * Works like module_invoke_all('cron_queue_info'), but adds
-   * a 'module' to each item.
-   *
-   * @return array
-   *   Cron queue definitions.
-   */
-  private function get_queues() {
-    if (!isset(self::$queues)) {
-      $queues = array();
-      foreach (module_implements('cron_queue_info') as $module) {
-        $items = module_invoke($module, 'cron_queue_info');
-        if (is_array($items)) {
-          foreach ($items as &$item) {
-            $item['module'] = $module;
-          }
-          $queues += $items;
-        }
-      }
-      drupal_alter('cron_queue_info', $queues);
-      self::$queues = $queues;
-    }
-    return $queues;
-  }
-
-  /**
-   * Implements hook_cronapi().
-   */
-  public function cronapi() {
-    $items = array();
-    if (!variable_get($this->key . '_enabled', TRUE)) {
-      return $items;
-    }
-
-    // Grab the defined cron queues.
-    $queues = self::get_queues();
-
-    foreach ($queues as $name => $info) {
-      if (!empty($info['skip on cron'])) {
-        continue;
-      }
-
-      $items['queue_' . $name] = array(
-        'title' => t('Queue: @name', array('@name' => $name)),
-        'callback' => array(get_class($this), 'worker_callback'),
-        'scheduler' => array(
-          'simple' => array(
-            'rules' => array('* * * * *'),
-          ),
-          'crontab' => array(
-            'rules' => array('* * * * *'),
-          ),
-        ),
-        'settings' => array(
-          'queue' => array(
-            'name' => $name,
-            'worker callback' => $info['worker callback'],
-          ),
-        ),
-        'tags' => array('queue', 'core', 'killable'),
-        'module' => $info['module'],
-      );
-      if (isset($info['time'])) {
-        $items['queue_' . $name]['settings']['queue']['time'] = $info['time'];
-      }
-    }
-
-    return $items;
-  }
-
-  /**
-   * Process a cron queue.
-   *
-   * This is a wrapper around the cron queues "worker callback".
-   *
-   * @param CronJob $job
-   *   The job being run.
-   */
-  static public function worker_callback($job) {
-    $settings = $job->getPluginSettings('settings');
-    $queue = DrupalQueue::get($settings['queue']['name']);
-    $function = $settings['queue']['worker callback'];
-
-    $end = microtime(TRUE) + $settings['queue']['time'];
-    $items = 0;
-    while (microtime(TRUE) < $end) {
-      if ($job->getSignal('kill')) {
-        \Drupal::logger('ultimate_cron')->warning('kill signal recieved');
-        break;
-      }
-
-      $item = $queue->claimItem($settings['queue']['lease_time']);
-      if (!$item) {
-        if ($settings['queue']['empty_delay']) {
-          usleep($settings['queue']['empty_delay'] * 1000000);
-          continue;
-        }
-        else {
-          break;
-        }
-      }
-      try {
-        if ($settings['queue']['item_delay']) {
-          if ($items == 0) {
-            // Move the boundary if using a throttle, to avoid waiting for nothing.
-            $end -= $settings['queue']['item_delay'] * 1000000;
-          }
-          else {
-            // Sleep before retrieving.
-            usleep($settings['queue']['item_delay'] * 1000000);
-          }
-        }
-        $function($item->data);
-        $queue->deleteItem($item);
-        $items++;
-      }
-      catch (Exception $e) {
-        // Just continue ...
-        \Drupal::logger($job->hook['module'])->error("Queue item @item_id from queue @queue failed with message @message", array(
-          '@item_id' => $item->item_id,
-          '@queue' => $settings['queue']['name'],
-          '@message' => $e->getMessage()
-        ));
-      }
-    }
-    \Drupal::logger($job->hook['module'])->info('Processed @items items from queue @queue', array(
-      '@items' => $items,
-      '@queue' => $settings['queue']['name'],
-    ));
-
-    // Re-throttle.
-    $job->getPlugin('settings', 'queue')->throttle($job);
-
-    return;
-  }
-
-  /**
-   * Implements hook_cron_alter().
-   */
-  public function cron_alter(&$jobs) {
-    $new_jobs = array();
-    foreach ($jobs as $job) {
-      if (!$this->isValid($job)) {
-        continue;
-      }
-      $settings = $job->getSettings();
-      if (isset($settings['settings']['queue']['name'])) {
-        if ($settings['settings']['queue']['throttle']) {
-          for ($i = 2; $i <= $settings['settings']['queue']['threads']; $i++) {
-            $name = $job->id() . '_' . $i;
-            $hook = $job->hook;
-            $hook['settings']['queue']['master'] = $job->id();
-            $hook['settings']['queue']['thread'] = $i;
-            $hook['name'] = $name;
-            $hook['title'] .= " (#$i)";
-            $hook['immutable'] = TRUE;
-            $new_jobs[$name] = ultimate_cron_prepare_job($name, $hook);
-            $new_jobs[$name]->settings = $settings + $new_jobs[$name]->settings;
-            $new_jobs[$name]->title = $job->title . " (#$i)";
-          }
-        }
-      }
-    }
-    $jobs += $new_jobs;
-  }
-
-  /**
-   * Implements hook_cron_alter().
-   */
-  public function cron_pre_schedule($job) {
-    $queue_name = !empty($job->hook['settings']['queue']['name']) ? $job->hook['settings']['queue']['name'] : FALSE;
-    if ($queue_name) {
-      if (empty(self::$throttled[$job->id()])) {
-        self::$throttled[$job->id()] = TRUE;
-        $this->throttle($job);
-      }
-    }
-  }
-
-  /**
-   * Default settings.
-   */
-  public function defaultSettings() {
-    return array(
-      'lease_time' => 30,
-      'empty_delay' => 0,
-      'item_delay' => 0,
-      'throttle' => FALSE,
-      'threads' => 4,
-      'threshold' => 10,
-      'time' => 15,
-    );
-  }
-
-  /**
-   * Settings form.
-   */
-  public function settingsForm(&$form, &$form_state, $job = NULL) {
-    $elements = &$form['settings'][$this->type][$this->name];
-    $values = &$form_state['values']['settings'][$this->type][$this->name];
-
-    $states = array();
-    if (!$job) {
-      $elements['enabled'] = array(
-        '#title' => t('Enable cron queue processing'),
-        '#description' => t('If enabled, cron queues will be processed by this plugin. If another cron queue plugin is installed, it may be necessary/beneficial to disable this plugin.'),
-        '#type' => 'checkbox',
-        '#default_value' => variable_get($this->key . '_enabled', TRUE),
-        '#fallback' => TRUE,
-      );
-      $states = array(
-        '#states' => array(
-          'visible' => array(
-            ':input[name="settings[' . $this->type . '][' . $this->name . '][enabled]"]' => array(
-              'checked' => TRUE,
-            ),
-          ),
-        ),
-      );
-    }
-
-    $elements['timeouts'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Timeouts'),
-    ) + $states;
-    $elements['timeouts']['lease_time'] = array(
-      '#parents' => array('settings', $this->type, $this->name, 'lease_time'),
-      '#title' => t("Queue lease time"),
-      '#type' => 'textfield',
-      '#default_value' => $values['lease_time'],
-      '#description' => t('Seconds to claim a cron queue item.'),
-      '#fallback' => TRUE,
-      '#required' => TRUE,
-    );
-    $elements['timeouts']['time'] = array(
-      '#parents' => array('settings', $this->type, $this->name, 'time'),
-      '#title' => t('Time'),
-      '#type' => 'textfield',
-      '#default_value' => $values['time'],
-      '#description' => t('Time in seconds to process items during a cron run.'),
-      '#fallback' => TRUE,
-      '#required' => TRUE,
-    );
-
-    $elements['delays'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Delays'),
-    ) + $states;
-    $elements['delays']['empty_delay'] = array(
-      '#parents' => array('settings', $this->type, $this->name, 'empty_delay'),
-      '#title' => t("Empty delay"),
-      '#type' => 'textfield',
-      '#default_value' => $values['empty_delay'],
-      '#description' => t('Seconds to delay processing of queue if queue is empty (0 = end job).'),
-      '#fallback' => TRUE,
-      '#required' => TRUE,
-    );
-    $elements['delays']['item_delay'] = array(
-      '#parents' => array('settings', $this->type, $this->name, 'item_delay'),
-      '#title' => t("Item delay"),
-      '#type' => 'textfield',
-      '#default_value' => $values['item_delay'],
-      '#description' => t('Seconds to wait between processing each item in a queue.'),
-      '#fallback' => TRUE,
-      '#required' => TRUE,
-    );
-
-    $elements['throttle'] = array(
-      '#title' => t('Throttle'),
-      '#type' => 'checkbox',
-      '#default_value' => $values['throttle'],
-      '#description' => t('Throttle queues using multiple threads.'),
-    );
-
-    $states = !$job ? $states : array(
-      '#states' => array(
-        'visible' => array(':input[name="settings[' . $this->type . '][' . $this->name . '][throttle]"]' => array('checked' => TRUE))
-      ),
-    );
-
-    $elements['throttling'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Throttling'),
-    ) + $states;
-    $elements['throttling']['threads'] = array(
-      '#parents' => array('settings', $this->type, $this->name, 'threads'),
-      '#title' => t('Threads'),
-      '#type' => 'textfield',
-      '#default_value' => $values['threads'],
-      '#description' => t('Number of threads to use for queues.'),
-      '#states' => array(
-        'visible' => array(':input[name="settings[' . $this->type . '][' . $this->name . '][throttle]"]' => array('checked' => TRUE))
-      ),
-      '#fallback' => TRUE,
-      '#required' => TRUE,
-    );
-    $elements['throttling']['threshold'] = array(
-      '#parents' => array('settings', $this->type, $this->name, 'threshold'),
-      '#title' => t('Threshold'),
-      '#type' => 'textfield',
-      '#default_value' => $values['threshold'],
-      '#description' => t('Number of items in queue required to activate the next cron job.'),
-      '#states' => array(
-        'visible' => array(':input[name="settings[' . $this->type . '][' . $this->name . '][throttle]"]' => array('checked' => TRUE))
-      ),
-      '#fallback' => TRUE,
-      '#required' => TRUE,
-    );
-  }
-
-  /**
-   * Form submit handler.
-   */
-  public function settingsFormSubmit(&$form, &$form_state, $job = NULL) {
-    if (!$job) {
-      $values = &$form_state['values']['settings'][$this->type][$this->name];
-      variable_set($this->key . '_enabled', $values['enabled']);
-      unset($values['enabled']);
-    }
-  }
-
-  /**
-   * Throttle queues.
-   *
-   * Enables or disables queue threads depending on remaining items in queue.
-   */
-  public function throttle($job) {
-    if (!empty($job->hook['settings']['queue']['master'])) {
-      // We always base the threads on the master.
-      $master_job = ultimate_cron_job_load($job->hook['settings']['queue']['master']);
-      $settings = $master_job->getSettings('settings');
-    }
-    else {
-      return;
-    }
-    if ($settings['queue']['throttle']) {
-      $queue = DrupalQueue::get($settings['queue']['name']);
-      $items = $queue->numberOfItems();
-      $thread = $job->hook['settings']['queue']['thread'];
-
-      $name = $master_job->name . '_' . $thread;
-      $status = empty($master_job->disabled) && ($items >= ($thread - 1) * $settings['queue']['threshold']);
-      $new_status = !$status ? TRUE : FALSE;
-      $old_status = ultimate_cron_job_get_status($name) ? TRUE : FALSE;
-      if ($old_status !== $new_status) {
-        $log_entry = $job->startLog(uniqid($job->id(), TRUE), 'throttling', ULTIMATE_CRON_LOG_TYPE_ADMIN);
-        $log_entry->log($job->id(), 'Job @status by queue throttling (items:@items, boundary:@boundary, threshold:@threshold)', array(
-          '@status' => $new_status ? t('disabled') : t('enabled'),
-          '@items' => $items,
-          '@boundary' => ($thread - 1) * $settings['queue']['threshold'],
-          '@threshold' => $settings['queue']['threshold'],
-        ), RfcLogLevel::INFO);
-        $log_entry->finish();
-        $job->dont_log = TRUE;
-        ultimate_cron_job_set_status($job, $new_status);
-        $job->disabled = $new_status;
-      }
-    }
-  }
-}
diff --git a/src/UltimateCron.php b/src/UltimateCron.php
index aa13157..22c9475 100644
--- a/src/UltimateCron.php
+++ b/src/UltimateCron.php
@@ -18,30 +18,31 @@ class UltimateCron extends Cron {
    */
   public function run() {
 
+    // Load the cron jobs in the right order.
+    $job_ids = \Drupal::entityQuery('ultimate_cron_job')
+      ->condition('status', TRUE)
+      ->sort('weight', 'ASC')
+
+      ->execute();
+
     $launcher_jobs = array();
-    foreach (CronJob::loadMultiple() as $job) {
-      if ($job->status()) {
-        /* @var \Drupal\Core\Plugin\DefaultPluginManager $manager */
-        $manager = \Drupal::service('plugin.manager.ultimate_cron.' . 'launcher');
-        $launcher = $manager->createInstance($job->getLauncherId());
-        $launcher_definition = $launcher->getPluginDefinition();
+    foreach (CronJob::loadMultiple($job_ids) as $job) {
+      /* @var \Drupal\Core\Plugin\DefaultPluginManager $manager */
+      $manager = \Drupal::service('plugin.manager.ultimate_cron.' . 'launcher');
+      $launcher = $manager->createInstance($job->getLauncherId());
+      $launcher_definition = $launcher->getPluginDefinition();
 
-        if (!isset($launchers) || in_array($launcher->getPluginId(), $launchers)) {
-          $launcher_jobs[$launcher_definition['id']]['launcher'] = $launcher;
-          $launcher_jobs[$launcher_definition['id']]['sort'] = array($launcher_definition['weight']);
-          $launcher_jobs[$launcher_definition['id']]['jobs'][$job->id()] = $job;
-          $launcher_jobs[$launcher_definition['id']]['jobs'][$job->id()]->sort = array($job->loadLatestLogEntry()->start_time);
-        }
+      if (!isset($launchers) || in_array($launcher->getPluginId(), $launchers)) {
+        $launcher_jobs[$launcher_definition['id']]['launcher'] = $launcher;
+        $launcher_jobs[$launcher_definition['id']]['sort'] = array($launcher_definition['weight']);
+        $launcher_jobs[$launcher_definition['id']]['jobs'][$job->id()] = $job;
+        $launcher_jobs[$launcher_definition['id']]['jobs'][$job->id()]->sort = array($job->loadLatestLogEntry()->start_time);
       }
     }
 
-    uasort($launcher_jobs, '_ultimate_cron_multi_column_sort');
-
     foreach ($launcher_jobs as $name => $launcher_job) {
-      //uasort($launcher_job['jobs'], '_ultimate_cron_multi_column_sort');
       $launcher_job['launcher']->launchJobs($launcher_job['jobs']);
     }
-    $this->processQueues();
     $this->setCronLastTime();
 
     return TRUE;
diff --git a/ultimate_cron.module b/ultimate_cron.module
index 803b599..8f72d0a 100755
--- a/ultimate_cron.module
+++ b/ultimate_cron.module
@@ -4,7 +4,9 @@
  * Ultimate Cron. Extend cron functionality in Drupal.
  */
 
-use Drupal\Core\Database\Database;
+use Drupal\Core\Queue\RequeueException;
+use Drupal\Core\Queue\SuspendQueueException;
+use Drupal\ultimate_cron\CronJobInterface;
 use Drupal\ultimate_cron\CronPlugin;
 use Drupal\ultimate_cron\Logger\LoggerBase;
 use Drupal\ultimate_cron\PluginCleanupInterface;
@@ -174,8 +176,6 @@ function ultimate_cron_help($route_name, \Drupal\Core\Routing\RouteMatchInterfac
  * Adds clean up jobs for plugins.
  * */
 function ultimate_cron_cron() {
-  $items = array();
-
   $plugin_types = CronPlugin::getPluginTypes();
   foreach ($plugin_types as $plugin_type => $info) {
     foreach (ultimate_cron_plugin_load_all($plugin_type) as $name => $plugin) {
@@ -184,8 +184,52 @@ function ultimate_cron_cron() {
       }
     }
   }
+}
 
-  return $items;
+/**
+ * Cron callback for queue worker cron jobs.
+ */
+function ultimate_cron_queue_callback($job_id) {
+  $queue_name = str_replace(CronJobInterface::QUEUE_ID_PREFIX, '', $job_id);
+
+  $queue_manager = \Drupal::service('plugin.manager.queue_worker');
+  $queue_factory = \Drupal::service('queue');
+
+  $info = $queue_manager->getDefinition($queue_name);
+
+  // Make sure every queue exists. There is no harm in trying to recreate
+  // an existing queue.
+  $queue_factory->get($queue_name)->createQueue();
+
+  /** @var \Drupal\Core\Queue\QueueWorkerInterface $queue_worker */
+  $queue_worker = $queue_manager->createInstance($queue_name);
+  $end = time() + (isset($info['cron']['time']) ? $info['cron']['time'] : 15);
+
+  /** @var \Drupal\Core\Queue\QueueInterface $queue */
+  $queue = $queue_factory->get($queue_name);
+  while (time() < $end && ($item = $queue->claimItem())) {
+    try {
+      $queue_worker->processItem($item->data);
+      $queue->deleteItem($item);
+    }
+    catch (RequeueException $e) {
+      // The worker requested the task be immediately requeued.
+      $queue->releaseItem($item);
+    }
+    catch (SuspendQueueException $e) {
+      // If the worker indicates there is a problem with the whole queue,
+      // release the item and skip to the next queue.
+      $queue->releaseItem($item);
+
+      watchdog_exception('cron', $e);
+
+    }
+    catch (\Exception $e) {
+      // In case of any other kind of exception, log it and leave the item
+      // in the queue to be processed again later.
+      watchdog_exception('ultimate_cron_queue', $e);
+    }
+  }
 }
 
 /**
diff --git a/ultimate_cron.services.yml b/ultimate_cron.services.yml
index e8fd717..828c827 100644
--- a/ultimate_cron.services.yml
+++ b/ultimate_cron.services.yml
@@ -25,4 +25,4 @@ services:
     arguments: ['@cache.signal', '@lock']
   ultimate_cron.discovery:
     class: Drupal\ultimate_cron\CronJobDiscovery
-    arguments: ['@module_handler']
+    arguments: ['@module_handler', '@plugin.manager.queue_worker']
