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..3e85453 100644
--- a/src/CronJobDiscovery.php
+++ b/src/CronJobDiscovery.php
@@ -1,13 +1,10 @@
 <?php
-/**
- * @file
- * Contains \Drupal\ultimate_cron\CronJobDiscovery.
- *
- * Cron Job helper class.
- */
+
 namespace Drupal\ultimate_cron;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Queue\QueueWorkerManagerInterface;
 use Drupal\ultimate_cron\Entity\CronJob;
 
 /**
@@ -21,22 +18,69 @@ class CronJobDiscovery {
   protected $moduleHandler;
 
   /**
+   * @var \Drupal\Core\Queue\QueueWorkerManagerInterface
+   */
+  protected $queueManager;
+
+  /**
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
    * 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, ConfigFactoryInterface $config_factory) {
     $this->moduleHandler = $module_handler;
+    $this->queueManager = $queue_manager;
+    $this->configFactory = $config_factory;
   }
 
   /**
    * 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);
     }
+
+    if (!$this->configFactory->get('ultimate_cron.settings')->get('queue.enabled')) {
+      return;
+    }
+
+    // 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..42491c2 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,22 @@ use Drupal\Core\Entity\EntityInterface;
  *
  * @see \Drupal\ultimate_cron\Entity\CronJob
  */
-class CronJobListBuilder extends ConfigEntityListBuilder {
+class CronJobListBuilder extends DraggableListBuilder {
+
+  /**
+   * {@inheritdoc}
+   */
+  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 +46,28 @@ 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['module']['#wrapper_attributes']['title'] = $entity->getModuleDescription();
+    $row['scheduled']['label']['#markup'] = $entity->getPlugin('scheduler')->formatLabel($entity);
     if ($entity->isScheduled()) {
-      $row['scheduled']['data']['behind'] = $behind_icon;
-    }
-    else {
-      $row['scheduled'] = $entity->getPlugin('scheduler')->formatLabel($entity);
+      $row['scheduled']['behind'] = $behind_icon;
     }
     // 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/Form/GeneralSettingsForm.php b/src/Form/GeneralSettingsForm.php
index 4369af1..0395e63 100644
--- a/src/Form/GeneralSettingsForm.php
+++ b/src/Form/GeneralSettingsForm.php
@@ -110,16 +110,22 @@ class GeneralSettingsForm extends ConfigFormBase {
 
     $form['queue']['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.'),
+      '#description' => t('If enabled, queue workers are exposed as cron jobs and can be configured separately. When disabled, the standard queue processing is used. <strong>This feature is currently experimental, do not enable unless you need it.</strong>'),
       '#type' => 'checkbox',
-      '#default_value' => $config->get('queue.enabled', TRUE),
+      '#default_value' => $config->get('queue.enabled'),
       '#fallback' => TRUE,
     );
 
+    $queue_states = array(
+      '#states' => array(
+        'visible' => array(':input[name="queue[enabled]"]' => array('checked' => TRUE)),
+      ),
+    );
+
     $form['queue']['timeouts'] = array(
       '#type' => 'fieldset',
       '#title' => t('Timeouts'),
-    );
+    ) + $queue_states;
     $form['queue']['timeouts']['lease_time'] = array(
       '#title' => t("Queue lease time"),
       '#type' => 'number',
@@ -127,6 +133,7 @@ class GeneralSettingsForm extends ConfigFormBase {
       '#description' => t('Seconds to claim a cron queue item.'),
       '#fallback' => TRUE,
       '#required' => TRUE,
+      '#min' => 0,
     );
     $form['queue']['timeouts']['time'] = array(
       '#title' => t('Time'),
@@ -135,12 +142,13 @@ class GeneralSettingsForm extends ConfigFormBase {
       '#description' => t('Time in seconds to process items during a cron run.'),
       '#fallback' => TRUE,
       '#required' => TRUE,
+      '#min' => 0,
     );
 
     $form['queue']['delays'] = array(
       '#type' => 'fieldset',
       '#title' => t('Delays'),
-    );
+    ) + $queue_states;
     $form['queue']['delays']['empty_delay'] = array(
       '#title' => t("Empty delay"),
       '#type' => 'number',
@@ -148,6 +156,7 @@ class GeneralSettingsForm extends ConfigFormBase {
       '#description' => t('Seconds to delay processing of queue if queue is empty (0 = end job).'),
       '#fallback' => TRUE,
       '#required' => TRUE,
+      '#min' => 0,
     );
     $form['queue']['delays']['item_delay'] = array(
       '#title' => t("Item delay"),
@@ -156,18 +165,19 @@ class GeneralSettingsForm extends ConfigFormBase {
       '#description' => t('Seconds to wait between processing each item in a queue.'),
       '#fallback' => TRUE,
       '#required' => TRUE,
+      '#min' => 0,
     );
 
-    $states = array(
+    $throttle_states = array(
       '#states' => array(
         'visible' => array(':input[name="queue[throttle][enabled]"]' => array('checked' => TRUE)),
       ),
     );
 
     $form['queue']['throttle'] = array(
-        '#type' => 'fieldset',
-        '#title' => t('Throttling'),
-      );
+      '#type' => 'fieldset',
+      '#title' => t('Throttling'),
+    ) + $queue_states;
     $form['queue']['throttle']['enabled'] = array(
       '#title' => t('Throttle'),
       '#type' => 'checkbox',
@@ -181,7 +191,8 @@ class GeneralSettingsForm extends ConfigFormBase {
       '#description' => t('Number of threads to use for queues.'),
       '#fallback' => TRUE,
       '#required' => TRUE,
-    ) + $states;
+      '#min' => 0,
+    ) + $throttle_states;
     $form['queue']['throttle']['threshold'] = array(
       '#title' => t('Threshold'),
       '#type' => 'number',
@@ -189,7 +200,8 @@ class GeneralSettingsForm extends ConfigFormBase {
       '#description' => t('Number of items in queue required to activate the next cron job.'),
       '#fallback' => TRUE,
       '#required' => TRUE,
-    ) + $states;
+      '#min' => 0,
+    ) + $throttle_states;
 
     return parent::buildForm($form, $form_state);
   }
diff --git a/src/Tests/CronJobFormTest.php b/src/Tests/CronJobFormTest.php
index 64ff52d..fb961d1 100644
--- a/src/Tests/CronJobFormTest.php
+++ b/src/Tests/CronJobFormTest.php
@@ -111,8 +111,8 @@ class CronJobFormTest extends WebTestBase {
     $this->assertText(t('Disabled cron job @name.', array('@name' => $this->job_name)));
     $this->drupalGet('admin/config/system/cron/jobs');
     $this->assertFieldByXPath('//table/tbody/tr[1]/td[6]', 'Disabled');
-    $this->assertFieldByXPath('//table/tbody/tr[1]/td[7]/div/div/ul/li[1]/a', 'Enable');
-    $this->assertNoFieldByXPath('//table/tbody/tr[1]/td[7]/div/div/ul/li[1]/a', 'Run');
+    $this->assertFieldByXPath('//table/tbody/tr[1]/td[8]/div/div/ul/li[1]/a', 'Enable');
+    $this->assertNoFieldByXPath('//table/tbody/tr[1]/td[8]/div/div/ul/li[1]/a', 'Run');
 
     // Test enabling a job.
     $this->clickLink(t('Enable'), 0);
@@ -123,7 +123,7 @@ class CronJobFormTest extends WebTestBase {
     $this->assertText(t('Enabled cron job @name.', array('@name' => $this->job_name)));
     $this->drupalGet('admin/config/system/cron/jobs');
     $this->assertTrue(strpos($this->xpath('//table/tbody/tr[1]/td[6]/img')[0]->asXml(), 'core/misc/icons/73b355/check.svg'));
-    $this->assertFieldByXPath('//table/tbody/tr[1]/td[7]/div/div/ul/li[1]/a', 'Run');
+    $this->assertFieldByXPath('//table/tbody/tr[1]/td[8]/div/div/ul/li[1]/a', 'Run');
 
     // Test disabling a job with the checkbox on the edit page.
     $edit = array(
@@ -131,8 +131,8 @@ class CronJobFormTest extends WebTestBase {
     );
     $this->drupalPostForm('admin/config/system/cron/jobs/manage/' . $this->job_id, $edit, t('Save'));
     $this->assertFieldByXPath('//table/tbody/tr[1]/td[6]', 'Disabled');
-    $this->assertFieldByXPath('//table/tbody/tr[1]/td[7]/div/div/ul/li[1]/a', 'Enable');
-    $this->assertNoFieldByXPath('//table/tbody/tr[1]/td[7]/div/div/ul/li[1]/a', 'Run');
+    $this->assertFieldByXPath('//table/tbody/tr[1]/td[8]/div/div/ul/li[1]/a', 'Enable');
+    $this->assertNoFieldByXPath('//table/tbody/tr[1]/td[8]/div/div/ul/li[1]/a', 'Run');
 
     // Test enabling a job with the checkbox on the edit page.
     $edit = array(
@@ -140,7 +140,7 @@ class CronJobFormTest extends WebTestBase {
     );
     $this->drupalPostForm('admin/config/system/cron/jobs/manage/' . $this->job_id, $edit, t('Save'));
     $this->assertTrue(strpos($this->xpath('//table/tbody/tr[1]/td[6]/img')[0]->asXml(), 'core/misc/icons/73b355/check.svg'));
-    $this->assertFieldByXPath('//table/tbody/tr[1]/td[7]/div/div/ul/li[1]/a', 'Run');
+    $this->assertFieldByXPath('//table/tbody/tr[1]/td[8]/div/div/ul/li[1]/a', 'Run');
 
     $this->drupalGet('admin/config/system/cron/jobs');
 
@@ -170,7 +170,7 @@ class CronJobFormTest extends WebTestBase {
 
     // Assert that the invalid cron job is displayed properly.
     $this->assertFieldByXPath('//table/tbody/tr[1]/td[6]', 'Missing');
-    $this->assertFieldByXPath('//table/tbody/tr[1]/td[7]/div/div/ul/li/a', 'Delete');
+    $this->assertFieldByXPath('//table/tbody/tr[1]/td[8]/div/div/ul/li/a', 'Delete');
 
     // Test deleting a job (only possible if invalid cron job).
     $this->clickLink(t('Delete'), 0);
diff --git a/src/UltimateCron.php b/src/UltimateCron.php
index aa13157..ec3558f 100644
--- a/src/UltimateCron.php
+++ b/src/UltimateCron.php
@@ -6,42 +6,86 @@
 
 namespace Drupal\ultimate_cron;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Cron;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Lock\LockBackendInterface;
+use Drupal\Core\Queue\QueueFactory;
+use Drupal\Core\Queue\QueueWorkerManagerInterface;
+use Drupal\Core\Session\AccountSwitcherInterface;
+use Drupal\Core\State\StateInterface;
 use Drupal\ultimate_cron\Entity\CronJob;
+use Psr\Log\LoggerInterface;
 
 /**
  * The Ultimate Cron service.
  */
 class UltimateCron extends Cron {
+
+  /**
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * Constructs a cron object.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler
+   * @param \Drupal\Core\Lock\LockBackendInterface $lock
+   *   The lock service.
+   * @param \Drupal\Core\Queue\QueueFactory $queue_factory
+   *   The queue service.
+   * @param \Drupal\Core\State\StateInterface $state
+   *   The state service.
+   * @param \Drupal\Core\Session\AccountSwitcherInterface $account_switcher
+   *    The account switching service.
+   * @param \Psr\Log\LoggerInterface $logger
+   *   A logger instance.
+   * @param \Drupal\Core\Queue\QueueWorkerManagerInterface
+   *   The queue plugin manager.
+   */
+  public function __construct(ModuleHandlerInterface $module_handler, LockBackendInterface $lock, QueueFactory $queue_factory, StateInterface $state, AccountSwitcherInterface $account_switcher, LoggerInterface $logger, QueueWorkerManagerInterface $queue_manager, ConfigFactoryInterface $config_factory) {
+    parent::__construct($module_handler, $lock, $queue_factory, $state, $account_switcher, $logger, $queue_manager);
+    $this->configFactory = $config_factory;
+  }
+
   /**
    * {@inheritdoc}
    */
   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();
+
+    // Run standard queue processing if our own handling is disabled.
+    if (!$this->configFactory->get('ultimate_cron.settings')->get('queue.enabled')) {
+      $this->processQueues();
+    }
+
     $this->setCronLastTime();
 
     return TRUE;
diff --git a/src/UltimateCronServiceProvider.php b/src/UltimateCronServiceProvider.php
index 965559b..bd724df 100644
--- a/src/UltimateCronServiceProvider.php
+++ b/src/UltimateCronServiceProvider.php
@@ -8,6 +8,7 @@ namespace Drupal\ultimate_cron;
 
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\DependencyInjection\ServiceProviderBase;
+use Symfony\Component\DependencyInjection\Reference;
 
 /**
  * Service Provider for File entity.
@@ -20,5 +21,6 @@ class UltimateCronServiceProvider extends ServiceProviderBase {
   public function alter(ContainerBuilder $container) {
     $definition = $container->getDefinition('cron');
     $definition->setClass('Drupal\ultimate_cron\UltimateCron');
+    $definition->addArgument(new Reference('config.factory'));
   }
 }
diff --git a/ultimate_cron.module b/ultimate_cron.module
index 803b599..89750cb 100755
--- a/ultimate_cron.module
+++ b/ultimate_cron.module
@@ -4,8 +4,11 @@
  * 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\Entity\CronJob;
 use Drupal\ultimate_cron\Logger\LoggerBase;
 use Drupal\ultimate_cron\PluginCleanupInterface;
 
@@ -174,8 +177,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 +185,62 @@ 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);
+
+  $job = CronJob::load($job_id);
+
+  $queue_manager = \Drupal::service('plugin.manager.queue_worker');
+  $queue_factory = \Drupal::service('queue');
+
+  $config = \Drupal::config('ultimate_cron.settings');
+
+  $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($config->get('queue.')))) {
+    // Check kill signal.
+    if ($job->getSignal('kill')) {
+      \Drupal::logger('ultimate_cron')->warning('Kill signal received for job @job_id', ['@job_id' => $job_id]);
+      break;
+    }
+
+    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..c08a15a 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', '@config.factory']
