diff --git a/core/includes/form.inc b/core/includes/form.inc
index c98e9e8..4382723 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -6,11 +6,12 @@
  */
 
 use Drupal\Component\Utility\UrlHelper;
+use Drupal\Core\Batch\Batch;
+use Drupal\Core\Batch\BatchQueueController;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Render\Element\RenderElement;
 use Drupal\Core\Template\Attribute;
 use Drupal\Core\Url;
-use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Prepares variables for select element templates.
@@ -662,9 +663,10 @@ function template_preprocess_form_element_label(&$variables) {
  * 'finished' callback. Batch sets are processed sequentially, with the progress
  * bar starting afresh for each new set.
  *
- * @param $batch_definition
- *   An associative array defining the batch, with the following elements (all
- *   are optional except as noted):
+ * @param \Drupal\Core\Batch\Batch|array $batch_definition
+ *   An object representing the batch or an associative array defining the
+ *   batch. If an array is used then it has the following elements (all are
+ *   optional except as noted):
  *   - operations: (required) Array of operations to be performed, where each
  *     item is an array consisting of the name of an implementation of
  *     callback_batch_operation() and an array of parameter.
@@ -709,61 +711,15 @@ function template_preprocess_form_element_label(&$variables) {
  *       Typically, the class will either be \Drupal\Core\Queue\Batch or
  *       \Drupal\Core\Queue\BatchMemory. Defaults to Batch if progressive is
  *       TRUE, or to BatchMemory if progressive is FALSE.
+ *
+ * @deprecated as of Drupal 8.2.x, will be removed in Drupal 9.0.0. Create a
+ *   \Drupal\Core\Batch\Batch object and use the enqueue() function.
  */
 function batch_set($batch_definition) {
-  if ($batch_definition) {
-    $batch =& batch_get();
-
-    // Initialize the batch if needed.
-    if (empty($batch)) {
-      $batch = array(
-        'sets' => array(),
-        'has_form_submits' => FALSE,
-      );
-    }
-
-    // Base and default properties for the batch set.
-    $init = array(
-      'sandbox' => array(),
-      'results' => array(),
-      'success' => FALSE,
-      'start' => 0,
-      'elapsed' => 0,
-    );
-    $defaults = array(
-      'title' => t('Processing'),
-      'init_message' => t('Initializing.'),
-      'progress_message' => t('Completed @current of @total.'),
-      'error_message' => t('An error has occurred.'),
-      'css' => array(),
-    );
-    $batch_set = $init + $batch_definition + $defaults;
-
-    // Tweak init_message to avoid the bottom of the page flickering down after
-    // init phase.
-    $batch_set['init_message'] .= '<br/>&nbsp;';
-
-    // The non-concurrent workflow of batch execution allows us to save
-    // numberOfItems() queries by handling our own counter.
-    $batch_set['total'] = count($batch_set['operations']);
-    $batch_set['count'] = $batch_set['total'];
-
-    // Add the set to the batch.
-    if (empty($batch['id'])) {
-      // The batch is not running yet. Simply add the new set.
-      $batch['sets'][] = $batch_set;
-    }
-    else {
-      // The set is being added while the batch is running. Insert the new set
-      // right after the current one to ensure execution order, and store its
-      // operations in a queue.
-      $index = $batch['current_set'] + 1;
-      $slice1 = array_slice($batch['sets'], 0, $index);
-      $slice2 = array_slice($batch['sets'], $index);
-      $batch['sets'] = array_merge($slice1, array($batch_set), $slice2);
-      _batch_populate_queue($batch, $index);
-    }
+  if (!($batch_definition instanceof Batch)) {
+    $batch_definition = Batch::createFromArray($batch_definition);
   }
+  $batch_definition->enqueue();
 }
 
 /**
@@ -783,94 +739,21 @@ function batch_set($batch_definition) {
  *   automatically by the standard batch processing pipeline (and which takes
  *   precedence over this parameter).
  * @param \Drupal\Core\Url $url
- *   (optional - should only be used for separate scripts like update.php)
- *   URL of the batch processing page.
- * @param $redirect_callback
+ *   (optional) URL of the batch processing page.
+ *   Should only be used for separate scripts like update.php.
+ * @param string $redirect_callback
  *   (optional) Specify a function to be called to redirect to the progressive
  *   processing page.
  *
  * @return \Symfony\Component\HttpFoundation\RedirectResponse|null
  *   A redirect response if the batch is progressive. No return value otherwise.
+ *
+ * @deprecated as of Drupal 8.2.x, will be removed in Drupal 9.0.0. Use
+ *   \Drupal\Core\Batch\Batch::process() instead or the process() function on
+ *   an existing Batch object.
  */
 function batch_process($redirect = NULL, Url $url = NULL, $redirect_callback = NULL) {
-  $batch =& batch_get();
-
-  if (isset($batch)) {
-    // Add process information
-    $process_info = array(
-      'current_set' => 0,
-      'progressive' => TRUE,
-      'url' => isset($url) ? $url : Url::fromRoute('system.batch_page.html'),
-      'source_url' => Url::fromRouteMatch(\Drupal::routeMatch()),
-      'batch_redirect' => $redirect,
-      'theme' => \Drupal::theme()->getActiveTheme()->getName(),
-      'redirect_callback' => $redirect_callback,
-    );
-    $batch += $process_info;
-
-    // The batch is now completely built. Allow other modules to make changes
-    // to the batch so that it is easier to reuse batch processes in other
-    // environments.
-    \Drupal::moduleHandler()->alter('batch', $batch);
-
-    // Assign an arbitrary id: don't rely on a serial column in the 'batch'
-    // table, since non-progressive batches skip database storage completely.
-    $batch['id'] = db_next_id();
-
-    // Move operations to a job queue. Non-progressive batches will use a
-    // memory-based queue.
-    foreach ($batch['sets'] as $key => $batch_set) {
-      _batch_populate_queue($batch, $key);
-    }
-
-    // Initiate processing.
-    if ($batch['progressive']) {
-      // Now that we have a batch id, we can generate the redirection link in
-      // the generic error message.
-      /** @var \Drupal\Core\Url $batch_url */
-      $batch_url = $batch['url'];
-      /** @var \Drupal\Core\Url $error_url */
-      $error_url = clone $batch_url;
-      $query_options = $error_url->getOption('query');
-      $query_options['id'] = $batch['id'];
-      $query_options['op'] = 'finished';
-      $error_url->setOption('query', $query_options);
-
-      $batch['error_message'] = t('Please continue to <a href=":error_url">the error page</a>', array(':error_url' => $error_url->toString(TRUE)->getGeneratedUrl()));
-
-      // Clear the way for the redirection to the batch processing page, by
-      // saving and unsetting the 'destination', if there is any.
-      $request = \Drupal::request();
-      if ($request->query->has('destination')) {
-        $batch['destination'] = $request->query->get('destination');
-        $request->query->remove('destination');
-      }
-
-      // Store the batch.
-      \Drupal::service('batch.storage')->create($batch);
-
-      // Set the batch number in the session to guarantee that it will stay alive.
-      $_SESSION['batches'][$batch['id']] = TRUE;
-
-      // Redirect for processing.
-      $query_options = $error_url->getOption('query');
-      $query_options['op'] = 'start';
-      $query_options['id'] = $batch['id'];
-      $batch_url->setOption('query', $query_options);
-      if (($function = $batch['redirect_callback']) && function_exists($function)) {
-        $function($batch_url->toString(), ['query' => $query_options]);
-      }
-      else {
-        return new RedirectResponse($batch_url->setAbsolute()->toString(TRUE)->getGeneratedUrl());
-      }
-    }
-    else {
-      // Non-progressive execution: bypass the whole progressbar workflow
-      // and execute the batch in one pass.
-      require_once __DIR__ . '/batch.inc';
-      _batch_process();
-    }
-  }
+  return BatchQueueController::process($redirect, $url, $redirect_callback);
 }
 
 /**
@@ -883,42 +766,7 @@ function &batch_get() {
   // that are part of the Batch API and need to reset the batch information may
   // call batch_get() and manipulate the result by reference. Functions that are
   // not part of the Batch API can also do this, but shouldn't.
-  static $batch = array();
-  return $batch;
-}
-
-/**
- * Populates a job queue with the operations of a batch set.
- *
- * Depending on whether the batch is progressive or not, the
- * Drupal\Core\Queue\Batch or Drupal\Core\Queue\BatchMemory handler classes will
- * be used. The name and class of the queue are added by reference to the
- * batch set.
- *
- * @param $batch
- *   The batch array.
- * @param $set_id
- *   The id of the set to process.
- */
-function _batch_populate_queue(&$batch, $set_id) {
-  $batch_set = &$batch['sets'][$set_id];
-
-  if (isset($batch_set['operations'])) {
-    $batch_set += array(
-      'queue' => array(
-        'name' => 'drupal_batch:' . $batch['id'] . ':' . $set_id,
-        'class' => $batch['progressive'] ? 'Drupal\Core\Queue\Batch' : 'Drupal\Core\Queue\BatchMemory',
-      ),
-    );
-
-    $queue = _batch_queue($batch_set);
-    $queue->createQueue();
-    foreach ($batch_set['operations'] as $operation) {
-      $queue->createItem($operation);
-    }
-
-    unset($batch_set['operations']);
-  }
+  return BatchQueueController::getBatches();
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Batch/Batch.php b/core/lib/Drupal/Core/Batch/Batch.php
new file mode 100644
index 0000000..a114afb
--- /dev/null
+++ b/core/lib/Drupal/Core/Batch/Batch.php
@@ -0,0 +1,301 @@
+<?php
+
+namespace Drupal\Core\Batch;
+
+/**
+ * Stores a domain object for a batch process.
+ *
+ * Example code to create a batch:
+ * @code
+ * $batch = Batch::create('Batch Title')
+ *   ->setTitle('Title can be changed.')
+ *   ->setFinishCallback('batch_example_finished_callback')
+ *   ->setInitMessage('The initialization message (optional)');
+ * for ($i = 0; $i < 1000; $i++) {
+ *   $batch->addOperation('batch_example_callback', array($i + 1));
+ * }
+ * $batch->enqueue();
+ * @endcode
+ */
+class Batch {
+
+  protected $operations = [];
+  protected $title;
+  protected $init_message;
+  protected $progress_message;
+  protected $error_message;
+  protected $finished;
+  protected $file;
+  protected $css = [];
+  protected $url_options = [];
+  protected $progressive;
+  protected $queue;
+
+  /**
+   * Constructs a new Batch instance.
+   *
+   * @param string $title
+   *   The title.
+   */
+  public function __construct($title = NULL) {
+    $this->setTitle(is_null($title) ? 'Processing' : $title);
+    $this->setInitMessage('Initializing.');
+    $this->setProgressMessage('Completed @current of @total.');
+    $this->setErrorMessage('An error has occurred.');
+  }
+
+  /**
+   * Static constructor for a batch process.
+   *
+   * @param string $title
+   *   The title.
+   *
+   * @return static
+   *   A new object.
+   */
+  public static function create($title = NULL) {
+    return new static($title);
+  }
+
+  /**
+   * Creates a \Drupal\Core\Batch\Batch object from an array.
+   *
+   * @param array $batch_definition
+   *   An array of values to use for the new object.
+   *
+   * @return static
+   *   A new initialized object.
+   */
+  public static function createFromArray(array $batch_definition) {
+    $new_batch = new static(isset($batch_definition['title']) ? $batch_definition['title'] : NULL);
+
+    foreach ($batch_definition as $key => $value) {
+      $new_batch->{$key} = $value;
+    }
+
+    return $new_batch;
+  }
+
+  /**
+   * Sets the title.
+   *
+   * @param string $title
+   *   The title.
+   *
+   * @return $this
+   */
+  public function setTitle($title) {
+    $this->title = $title;
+    return $this;
+  }
+
+  /**
+   * Sets the finished callback.
+   *
+   * This callback will be executed if the batch process is done.
+   *
+   * @param string $callback
+   *   The callback.
+   *
+   * @return $this
+   */
+  public function setFinishCallback($callback) {
+    $this->finished = $callback;
+    return $this;
+  }
+
+  /**
+   * Sets the displayed message while processing is initialized.
+   *
+   * @param string $message
+   *   The text to display. Defaults to t('Initializing.').
+   *
+   * @return $this
+   */
+  public function setInitMessage($message) {
+    $this->init_message = $message;
+    return $this;
+  }
+
+  /**
+   * Sets the message to display when the batch is being processed.
+   *
+   * @param string $message
+   *   The text to display.  Available placeholders are '@current',
+   *   '@remaining', '@total', '@percentage', '@estimate' and '@elapsed'.
+   *   Defaults to t('Completed @current of @total.').
+   *
+   * @return $this
+   */
+  public function setProgressMessage($message) {
+    $this->progress_message = $message;
+    return $this;
+  }
+
+  /**
+   * Sets the message to display if an error occurs while processing.
+   *
+   * @param string $message
+   *   The text to display. Defaults to t('An error has occurred.').
+   *
+   * @return $this
+   */
+  public function setErrorMessage($message) {
+    $this->error_message = $message;
+    return $this;
+  }
+
+  /**
+   * Sets the file that contains the callback functions.
+   *
+   * The path should be relative to base_path(), and thus should be built using
+   * drupal_get_path(). Defaults to {module_name}.module.
+   *
+   * @param string $filename
+   *   The path to the file.
+   *
+   * @return $this
+   */
+  public function setFile($filename) {
+    $this->file = $filename;
+    return $this;
+  }
+
+  /**
+   * Sets the location of css files.
+   *
+   * Adds the CSS files for use on the progress page. Any previously added CSS
+   * files are removed. Use \Drupal\Core\Batch\Batch::addCss() to add a file.
+   *
+   * @param array $filenames
+   *   The css files to be used.
+   *
+   * @return $this
+   */
+  public function setCss(array $filenames) {
+    $this->css = $filenames;
+    return $this;
+  }
+
+  /**
+   * Sets the options for redirect URLs.
+   *
+   * @param array $options
+   *   The options to use.
+   *
+   * @return $this
+   *
+   * @see \Drupal\Core\Url
+   */
+  public function setUrlOptions(array $options = []) {
+    $this->url_options = $options;
+    return $this;
+  }
+
+  /**
+   * Sets the batch to run progressively.
+   *
+   * @param bool $is_progressive
+   *   TRUE indicates that the batch will run in more than one run. FALSE
+   *   (default) indicates that the batch will finish in a single run.
+   *
+   * @return $this
+   */
+  public function setProgressive($is_progressive) {
+    $this->progressive = $is_progressive;
+    return $this;
+  }
+
+  /**
+   * Sets or removes an override for the default queue.
+   *
+   * @param string $name
+   *   The unique identifier for the queue.
+   * @param string $class
+   *   The name of a class that implements \Drupal\Core\Queue\QueueInterface,
+   *   including the full namespace but not starting with a backslash. It must
+   *   have a constructor with two arguments: $name and a
+   *   \Drupal\Core\Database\Connection object. Typically, the class will either
+   *   be \Drupal\Core\Queue\Batch or \Drupal\Core\Queue\BatchMemory. Defaults
+   *   to Batch if progressive is TRUE, or to BatchMemory if progressive is
+   *   FALSE.
+   *
+   * @return $this
+   */
+  public function setQueue($name, $class) {
+    if (is_null($name) && is_null($class)) {
+      $this->queue = NULL;
+    }
+    else {
+      $this->queue = array(
+        'name' => $name,
+        'class' => $class,
+      );
+    }
+    return $this;
+  }
+
+  /**
+   * Adds a batch operation.
+   *
+   * @param string $callback
+   *   The name of the callback function.
+   * @param array $arguments
+   *   An array of arguments to pass to the callback function.
+   *
+   * @return $this
+   */
+  public function addOperation($callback, $arguments = []) {
+    $this->operations[] = [$callback, $arguments];
+    return $this;
+  }
+
+  /**
+   * Adds a CSS file to be used on the process page.
+   *
+   * @param string $filename
+   *   The CSS file to use.
+   *
+   * @return $this
+   */
+  public function addCss($filename) {
+    $this->css[] = $filename;
+    return $this;
+  }
+
+  /**
+   * Places the batch in the queue to be processed.
+   *
+   * @return $this
+   */
+  public function enqueue() {
+    BatchQueueController::enqueue($this);
+    return $this;
+  }
+
+  /**
+   * Converts a \Drupal\Core\Batch\Batch object into an array.
+   *
+   * @return array
+   *   The array representation of the object.
+   */
+  public function toArray() {
+    $array = [];
+    foreach ($this as $key => $value) {
+      if (!is_null($value)) {
+        $array[$key] = $value;
+      }
+      else {
+        switch ($key) {
+          case 'operations':
+          case 'css':
+          case 'url_options':
+            $array[$key] = [];
+        }
+      }
+    }
+
+    return $array;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Batch/BatchQueueController.php b/core/lib/Drupal/Core/Batch/BatchQueueController.php
new file mode 100644
index 0000000..b83204f
--- /dev/null
+++ b/core/lib/Drupal/Core/Batch/BatchQueueController.php
@@ -0,0 +1,233 @@
+<?php
+
+namespace Drupal\Core\Batch;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Core\Url;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
+/**
+ * Handles operations on the batch processes to be handled.
+ */
+class BatchQueueController {
+
+  private static $batches = array();
+
+  /**
+   * Places the batch in the queue to be processed.
+   *
+   * @param \Drupal\Core\Batch\Batch $batch
+   *   The batch to place in the queue.
+   */
+  public static function enqueue(Batch $batch) {
+
+    // Initialize the batch if needed.
+    if (empty(self::$batches)) {
+      self::$batches = array(
+        'sets' => array(),
+        'has_form_submits' => FALSE,
+      );
+    }
+
+    $init = [
+      'sandbox' => [],
+      'results' => [],
+      'success' => FALSE,
+      'start' => 0,
+      'elapsed' => 0,
+    ];
+    $batch_set = $init + $batch->toArray();
+
+    // Make strings translatable.
+    if (is_string($batch_set['title'])) {
+      $batch_set['title'] = new TranslatableMarkup($batch_set['title']);
+    }
+    if (is_string($batch_set['init_message'])) {
+      $batch_set['init_message'] = new TranslatableMarkup($batch_set['init_message'] . '<br />&nbsp;');
+    }
+    elseif ($batch_set['init_message'] instanceof TranslatableMarkup) {
+      $batch_set['init_message'] = new TranslatableMarkup(
+        $batch_set['init_message']->getUntranslatedString() . '<br />&nbsp;'
+      );
+    }
+    if (is_string($batch_set['progress_message'])) {
+      $batch_set['progress_message'] = new TranslatableMarkup($batch_set['progress_message']);
+    }
+    if (is_string($batch_set['error_message'])) {
+      $batch_set['error_message'] = new TranslatableMarkup($batch_set['error_message']);
+    }
+
+    // The non-concurrent workflow of batch execution allows us to save
+    // numberOfItems() queries by handling our own counter.
+    $batch_set['total'] = count($batch_set['operations']);
+    $batch_set['count'] = $batch_set['total'];
+    // Add the set to the batch.
+    if (empty(self::$batches['id'])) {
+      // The batch is not running yet. Simply add the new set.
+      self::$batches['sets'][] = $batch_set;
+    }
+    else {
+      // The set is being added while the batch is running. Insert the new set
+      // right after the current one to ensure execution order, and store its
+      // operations in a queue.
+      $index = self::$batches['current_set'] + 1;
+      $slice1 = array_slice(self::$batches['sets'], 0, $index);
+      $slice2 = array_slice(self::$batches['sets'], $index);
+      self::$batches['sets'] = array_merge($slice1, array($batch_set), $slice2);
+      self::populateQueue($index);
+    }
+
+  }
+
+  /**
+   * Processes the batch.
+   *
+   * This function is generally not needed in form submit handlers;
+   * Form API takes care of batches that were set during form submission.
+   *
+   * @param \Drupal\Core\Url|string $redirect
+   *   (optional) Either path or Url object to redirect to when the batch has
+   *   finished processing. Note that to simply force a batch to (conditionally)
+   *   redirect to a custom location after it is finished processing but to
+   *   otherwise allow the standard form API batch handling to occur, it is not
+   *   necessary to call batch_process() and use this parameter. Instead, make
+   *   the batch 'finished' callback return an instance of
+   *   \Symfony\Component\HttpFoundation\RedirectResponse, which will be used
+   *   automatically by the standard batch processing pipeline (and which takes
+   *   precedence over this parameter).
+   * @param \Drupal\Core\Url $url
+   *   (optional) URL of the batch processing page.
+   *   Should only be used for separate scripts like update.php.
+   * @param string $redirect_callback
+   *   (optional) Specify a function to be called to redirect to the progressive
+   *   processing page.
+   *
+   * @return \Symfony\Component\HttpFoundation\RedirectResponse|null
+   *   A redirect response if the batch is progressive. No return value
+   *   otherwise.
+   */
+  public static function process($redirect = NULL, Url $url = NULL, $redirect_callback = NULL) {
+    if (isset(self::$batches)) {
+
+      // Add process information.
+      $process_info = [
+        'current_set' => 0,
+        'progressive' => TRUE,
+        'url' => isset($url) ? $url : Url::fromRoute('system.batch_page.html'),
+        'source_url' => Url::fromRouteMatch(\Drupal::routeMatch()),
+        'batch_redirect' => $redirect,
+        'theme' => \Drupal::theme()->getActiveTheme()->getName(),
+        'redirect_callback' => $redirect_callback,
+      ];
+      self::$batches += $process_info;
+
+      // The batch is now completely built. Allow other modules to make changes
+      // to the batch so that it is easier to reuse batch processes in other
+      // environments.
+      \Drupal::moduleHandler()->alter('batch', self::$batches);
+
+      // Assign an arbitrary id: don't rely on a serial column in the 'batch'
+      // table, since non-progressive batches skip database storage completely.
+      self::$batches['id'] = Database::getConnection()->nextId();
+
+      // Move operations to a job queue. Non-progressive batches will use a
+      // memory-based queue.
+      foreach (self::$batches['sets'] as $key => $batch_set) {
+        self::populateQueue($key);
+      }
+
+      // Initiate processing.
+      if (self::$batches['progressive']) {
+        // Now that we have a batch id, we can generate the redirection link in
+        // the generic error message.
+        /** @var \Drupal\Core\Url $batch_url */
+        $batch_url = self::$batches['url'];
+        /** @var \Drupal\Core\Url $error_url */
+        $error_url = clone $batch_url;
+        $query_options = $error_url->getOption('query');
+        $query_options['id'] = self::$batches['id'];
+        $query_options['op'] = 'finished';
+        $error_url->setOption('query', $query_options);
+
+        self::$batches['error_message'] = t('Please continue to <a href=":error_url">the error page</a>', array(':error_url' => $error_url->toString(TRUE)->getGeneratedUrl()));
+
+        // Clear the way for the redirection to the batch processing page, by
+        // saving and un-setting the 'destination', if there is any.
+        $request = \Drupal::request();
+        if ($request->query->has('destination')) {
+          self::$batches['destination'] = $request->query->get('destination');
+          $request->query->remove('destination');
+        }
+
+        // Store the batch.
+        \Drupal::service('batch.storage')->create(self::$batches);
+
+        // Set the batch number in the session to guarantee that it will stay
+        // alive.
+        $_SESSION['batches'][self::$batches['id']] = TRUE;
+
+        // Redirect for processing.
+        $query_options = $error_url->getOption('query');
+        $query_options['op'] = 'start';
+        $query_options['id'] = self::$batches['id'];
+        $batch_url->setOption('query', $query_options);
+        if (($function = self::$batches['redirect_callback']) && function_exists($function)) {
+          $function($batch_url->toString(), ['query' => $query_options]);
+        }
+        else {
+          return new RedirectResponse($batch_url->setAbsolute()->toString(TRUE)->getGeneratedUrl());
+        }
+      }
+      else {
+        // Non-progressive execution: bypass the whole progressbar workflow
+        // and execute the batch in one pass.
+        require_once DRUPAL_ROOT . '/core/includes/batch.inc';
+        _batch_process();
+      }
+    }
+
+    return NULL;
+  }
+
+  /**
+   * Retrieves the current batch.
+   */
+  public static function &getBatches() {
+    return self::$batches;
+  }
+
+  /**
+   * Populates a job queue with the operations of a batch set.
+   *
+   * Depending on whether the batch is progressive or not, the
+   * Drupal\Core\Queue\Batch or Drupal\Core\Queue\BatchMemory handler classes
+   * will be used. The name and class of the queue are added by reference to the
+   * batch set.
+   *
+   * @param int $set_id
+   *   The id of the set to process.
+   */
+  protected static function populateQueue($set_id = 0) {
+    $batch = &self::$batches;
+    $batch_set = &$batch['sets'][$set_id];
+
+    if (isset($batch_set['operations'])) {
+      $batch_set += array(
+        'queue' => array(
+          'name' => 'drupal_batch:' . $batch['id'] . ':' . $set_id,
+          'class' => $batch['progressive'] ? 'Drupal\Core\Queue\Batch' : 'Drupal\Core\Queue\BatchMemory',
+        ),
+      );
+
+      $queue = _batch_queue($batch_set);
+      $queue->createQueue();
+      foreach ($batch_set['operations'] as $operation) {
+        $queue->createItem($operation);
+      }
+
+      unset($batch_set['operations']);
+    }
+  }
+
+}
