diff --git a/core/lib/Drupal/Core/Annotation/QueueWorker.php b/core/lib/Drupal/Core/Annotation/QueueWorker.php
index 354642a72c60e571889e1748948cdebea46c0d79..a8375e6d3bb85f6738ce01915d1b2649da07170c 100644
--- a/core/lib/Drupal/Core/Annotation/QueueWorker.php
+++ b/core/lib/Drupal/Core/Annotation/QueueWorker.php
@@ -52,13 +52,15 @@ class QueueWorker extends Plugin {
   public $title;
 
   /**
-   * An associative array containing an optional key.
+   * An associative array containing optional keys.
    *
    * This property is optional and it does not need to be declared.
    *
    * Available keys:
    * - time (optional): How much time Drupal cron should spend on calling this
    *   worker in seconds. Defaults to 15.
+   * - lease_time: (optional) How long the lease is for a queue item when
+   *   called from cron in seconds. Defaults to 30.
    *
    * @var array
    */
diff --git a/core/lib/Drupal/Core/Cron.php b/core/lib/Drupal/Core/Cron.php
index 5464f7238d0e3e93f03bded24c6b02d84c0ec287..b8d8b8e1a4eb838f25b92dd60f0351ae3eeeb484 100644
--- a/core/lib/Drupal/Core/Cron.php
+++ b/core/lib/Drupal/Core/Cron.php
@@ -174,10 +174,10 @@ protected function processQueues() {
         $this->queueFactory->get($queue_name)->createQueue();
 
         $queue_worker = $this->queueManager->createInstance($queue_name);
-        $end = time() + ($info['cron']['time'] ?? 15);
+        $end = $this->time->getCurrentTime() + $info['cron']['time'] ?? static::DEFAULT_QUEUE_CRON_TIME;
         $queue = $this->queueFactory->get($queue_name);
-        $lease_time = isset($info['cron']['time']) ?: NULL;
-        while (time() < $end && ($item = $queue->claimItem($lease_time))) {
+        $lease_time = $info['cron']['lease_time'] ?? static::DEFAULT_QUEUE_CRON_LEASE_TIME;
+        while ($this->time->getCurrentTime() < $end && ($item = $queue->claimItem($lease_time))) {
           try {
             $queue_worker->processItem($item->data);
             $queue->deleteItem($item);
diff --git a/core/lib/Drupal/Core/CronInterface.php b/core/lib/Drupal/Core/CronInterface.php
index 98c3f37c6b7125ed43cb3f74d2a70f80423b9fc3..22a93f91ab50f2e6558bf56d99c2d695489afcdc 100644
--- a/core/lib/Drupal/Core/CronInterface.php
+++ b/core/lib/Drupal/Core/CronInterface.php
@@ -9,6 +9,16 @@
  */
 interface CronInterface {
 
+  /**
+   * The default time cron should execute each queue in seconds.
+   */
+  public const DEFAULT_QUEUE_CRON_TIME = 15;
+
+  /**
+   * The default lease time a queue item should get when called from cron.
+   */
+  public const DEFAULT_QUEUE_CRON_LEASE_TIME = 30;
+
   /**
    * Executes a cron run.
    *
diff --git a/core/lib/Drupal/Core/Queue/DatabaseQueue.php b/core/lib/Drupal/Core/Queue/DatabaseQueue.php
index 32a87feb323e319173cfc2b0c07011a10b611248..2af4360dcab2d070b28a64bed8fd2ce5da108f02 100644
--- a/core/lib/Drupal/Core/Queue/DatabaseQueue.php
+++ b/core/lib/Drupal/Core/Queue/DatabaseQueue.php
@@ -241,7 +241,7 @@ public function garbageCollection() {
     try {
       // Clean up the queue for failed batches.
       $this->connection->delete(static::TABLE_NAME)
-        ->condition('created', REQUEST_TIME - 864000, '<')
+        ->condition('created', \Drupal::time()->getRequestTime() - 864000, '<')
         ->condition('name', 'drupal_batch:%', 'LIKE')
         ->execute();
 
@@ -252,7 +252,7 @@ public function garbageCollection() {
           'expire' => 0,
         ])
         ->condition('expire', 0, '<>')
-        ->condition('expire', REQUEST_TIME, '<')
+        ->condition('expire', \Drupal::time()->getRequestTime(), '<')
         ->execute();
     }
     catch (\Exception $e) {
diff --git a/core/lib/Drupal/Core/Queue/QueueWorkerManager.php b/core/lib/Drupal/Core/Queue/QueueWorkerManager.php
index b1aa40f51c97a2f9e0a58d7cfee83252e36c29bb..c54135709fa0dbe05adb8e8da4efa97ccc1c13fc 100644
--- a/core/lib/Drupal/Core/Queue/QueueWorkerManager.php
+++ b/core/lib/Drupal/Core/Queue/QueueWorkerManager.php
@@ -34,20 +34,6 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
     $this->alterInfo('queue_info');
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function processDefinition(&$definition, $plugin_id) {
-    parent::processDefinition($definition, $plugin_id);
-
-    // Assign a default time if a cron is specified.
-    if (isset($definition['cron'])) {
-      $definition['cron'] += [
-        'time' => 15,
-      ];
-    }
-  }
-
   /**
    * {@inheritdoc}
    *
diff --git a/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestDatabaseDelayException.php b/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestDatabaseDelayException.php
index 93e4a1e2cb4b0381f387dc2b8ac20ac7397c8819..b9f3dbfe25a1682aa6c6552f988cfae7c12fdece 100644
--- a/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestDatabaseDelayException.php
+++ b/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestDatabaseDelayException.php
@@ -11,7 +11,10 @@
  * @QueueWorker(
  *   id = "cron_queue_test_database_delay_exception",
  *   title = @Translation("Database delay exception test"),
- *   cron = {"time" = 1}
+ *   cron = {
+ *     "time" = 1,
+ *     "lease_time" = 2
+ *   }
  * )
  */
 class CronQueueTestDatabaseDelayException extends QueueWorkerBase {
diff --git a/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestLeaseTime.php b/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestLeaseTime.php
new file mode 100644
index 0000000000000000000000000000000000000000..eab32490f2fd6eb88471f6c0ef7d33dff5935d85
--- /dev/null
+++ b/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestLeaseTime.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\cron_queue_test\Plugin\QueueWorker;
+
+use Drupal\Core\Queue\QueueWorkerBase;
+
+/**
+ * @QueueWorker(
+ *   id = "cron_queue_test_lease_time",
+ *   title = @Translation("Lease time test"),
+ *   cron = {
+ *     "time" = 5,
+ *     "lease_time" = 2
+ *   }
+ * )
+ */
+class CronQueueTestLeaseTime extends QueueWorkerBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function processItem($data) {
+    $state = \Drupal::state();
+    $count = $state->get('cron_queue_test_lease_time', 0);
+    $count++;
+    $state->set('cron_queue_test_lease_time', $count);
+    throw new \Exception('Leave me queued and leased!');
+  }
+
+}
diff --git a/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestMemoryDelayException.php b/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestMemoryDelayException.php
index 6548868608d86a7eb5f8af94e453317710104878..08f2c92ccbde91649abab9ea436e57180d6c38b5 100644
--- a/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestMemoryDelayException.php
+++ b/core/modules/system/tests/modules/cron_queue_test/src/Plugin/QueueWorker/CronQueueTestMemoryDelayException.php
@@ -11,7 +11,10 @@
  * @QueueWorker(
  *   id = "cron_queue_test_memory_delay_exception",
  *   title = @Translation("Memory delay exception test"),
- *   cron = {"time" = 1}
+ *   cron = {
+ *     "time" = 1,
+ *     "lease_time" = 2
+ *   }
  * )
  */
 class CronQueueTestMemoryDelayException extends QueueWorkerBase {
diff --git a/core/modules/system/tests/src/Kernel/System/CronQueueTest.php b/core/modules/system/tests/src/Kernel/System/CronQueueTest.php
index 7eef7520602df77c7d94a004b9dc13f11c16a402..940e1a52928396568f10c3fb8e197d40b7c14eb5 100644
--- a/core/modules/system/tests/src/Kernel/System/CronQueueTest.php
+++ b/core/modules/system/tests/src/Kernel/System/CronQueueTest.php
@@ -89,8 +89,8 @@ public function testDelayException() {
     // Get the queue worker plugin manager.
     $manager = $this->container->get('plugin.manager.queue_worker');
     $definitions = $manager->getDefinitions();
-    $this->assertNotEmpty($database_lease_time = $definitions['cron_queue_test_database_delay_exception']['cron']['time']);
-    $this->assertNotEmpty($memory_lease_time = $definitions['cron_queue_test_memory_delay_exception']['cron']['time']);
+    $this->assertNotEmpty($database_lease_time = $definitions['cron_queue_test_database_delay_exception']['cron']['lease_time']);
+    $this->assertNotEmpty($memory_lease_time = $definitions['cron_queue_test_memory_delay_exception']['cron']['lease_time']);
 
     // Create the necessary test data and run cron.
     $database->createItem('test');
@@ -120,6 +120,30 @@ public function testDelayException() {
     $this->assertEquals($this->currentTime + $memory_lease_time, reset($memory_queue_internal)->expire);
   }
 
+  /**
+   * Tests that leases are expiring correctly, also within the same request.
+   */
+  public function testLeaseTime() {
+    $queue = $this->container->get('queue')->get('cron_queue_test_lease_time');
+    $queue->createItem([$this->randomMachineName() => $this->randomMachineName()]);
+    $this->cron->run();
+    static::assertEquals(1, \Drupal::state()->get('cron_queue_test_lease_time'));
+    $this->cron->run();
+    static::assertEquals(1, \Drupal::state()->get('cron_queue_test_lease_time'));
+
+    // Set the expiration time to 3 seconds ago, so the lease should
+    // automatically expire.
+    \Drupal::database()
+      ->update(DatabaseQueue::TABLE_NAME)
+      ->fields(['expire' => $this->currentTime - 3])
+      ->execute();
+
+    $this->cron->run();
+    static::assertEquals(2, \Drupal::state()->get('cron_queue_test_lease_time'));
+    $this->cron->run();
+    static::assertEquals(2, \Drupal::state()->get('cron_queue_test_lease_time'));
+  }
+
   /**
    * Tests that exceptions thrown by workers are handled properly.
    */
@@ -145,7 +169,7 @@ public function testExceptions() {
     // @see \Drupal\Core\Cron::processQueues()
     $this->connection->update('queue')
       ->condition('name', 'cron_queue_test_exception')
-      ->fields(['expire' => REQUEST_TIME - 1])
+      ->fields(['expire' => \Drupal::time()->getRequestTime() - 1])
       ->execute();
     $this->cron->run();
     $this->assertEquals(2, \Drupal::state()->get('cron_queue_test_exception'));