Problem/Motivation

I have a long running queue worker and the current system doesn't have a way for queue workers to signal "I am not done yet".

Proposed resolution

Allow non-error releaseing an item.

Remaining tasks

User interface changes

API changes

New RequeueException.

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

chx created an issue. See original summary.

chx’s picture

Issue summary: View changes
Status: Active » Needs review
larowlan’s picture

Can we get a test for this, we probably already have something that throws the other exception

But love it

chx’s picture

FileSize
3.38 KB

Sure thing.

larowlan’s picture

+++ b/core/modules/system/src/Tests/System/CronQueueTest.php
@@ -61,5 +61,12 @@ public function testExceptions() {
+    $this->assertEqual(\Drupal::state()->get('cron_queue_test_requeue_exception'), 1);

Can you also assert that the queue size remains at 1?

Ta

larowlan’s picture

Also, I think we need some docs updates - and possibly a change notice.

chx’s picture

FileSize
1.9 KB
4.24 KB
larowlan’s picture

Status: Needs review » Reviewed & tested by the community

unless bot disagrees I think this is ready

neclimdul’s picture

Status: Reviewed & tested by the community » Needs work

I'm not really keen on using exceptions for control flow but the idea works.

  1. +++ b/core/lib/Drupal/Core/Cron.php
    @@ -168,6 +169,10 @@ protected function processQueues() {
    +          catch (RequeueException $e) {
    +            // This item needs more time to be processed.
    +            $queue->releaseItem($item);
    

    Lets at least change the wording around the exception. The comments about "needs more time" imply things about why the exception was thrown when it could be anything. A resource isn't available yet, it wants to hand off to a different worker, the third moon of Jupiter was out of alignment, the task should only be run on Mondays...

    Lets just say "the worker requested the task be immediately requeued" or something along those lines.

    Similar changes to the change log.

  2. +++ b/core/lib/Drupal/Core/Queue/RequeueException.php
    @@ -0,0 +1,14 @@
    +/**
    + * @file
    + * Contains \Drupal\Core\Queue\RequeueException.
    + */
    +
    +
    +namespace Drupal\Core\Queue;
    

    Extra line before namespace.

chx’s picture

Status: Needs work » Needs review
FileSize
4.29 KB
943 bytes

Updated the change notice too.

cosmicdreams’s picture

Status: Needs review » Reviewed & tested by the community

@neclimdul isn't that the reason why PHP has Exception types, so that you can handle them conditionally if they occur? This patch looks good to me. If this was the pre-Drupal 8 era, I would suggest that a change notice be written for it as it sounds like a nifty idea that developers would want to know more about.

Edit: my bad, you've already got the change noticed handled.

catch’s picture

@neclimdul isn't that the reason why PHP has Exception types, so that you can handle them conditionally if they occur?

Well it does, but they should really be used for errors (which might have different types), whereas this is not an error, it's just "Not right now thanks".

I opened #2670866: Add return values to QueueWorkerInterface::processItem() instead of using exceptions for code flow to tackle that in 9.x, but I really don't see a way to do it in a bc-compatible way, so exceptions seems like the only choice here.

  • catch committed 6377fc1 on 8.1.x
    Issue #2667294 by chx: Allow for peaceful requeueing
    
catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.1.x, thanks!

neclimdul’s picture

Right, thanks catch. What I try to emphasis when using exceptions is that exceptions should be exceptional. Typed exceptions exist so you can handle different exceptional cases. That means there can be different flows based on the exception but they should not be used for flow.

The way I think of it is this, if you are developing a feature you expect the users to use, you should not be using exceptions. If you are recovering from something —an error or failure in state— then exceptions is appropriate.

I'm not convinced passes that litmus and so should not be handled by exceptions. The API around the return type is exactly why I hesitated though, thanks catch for opening the follow up. This seems like the right approach so we can get the feature in and being used but can develop the right solution.

chx’s picture

Status: Fixed » Needs review
FileSize
3.05 KB

Reopening with a possible new approach based on the followup; no need to make it D9 IMO.

Edit: this keeps backwards compatibility because there can't be a runner which currently returns this object as this object doesn't yet exist. Returning any scalar would not fit this criteria.

neclimdul’s picture

Thanks for taking my concerns to heart!

So thinking this though, the BC seems to cover the item runner, but I wonder about BC with worker threads. The API goes both ways of course. So if a similar implementation existed in Drush and you run your queue there, if it doesn't handle the return it would normally delete the item since an exception wasn't thrown. Then the item is lost rather then being completed correct?

chx’s picture

We can add __drupal_queue_api_version to $data passed to processItem and then the worker can decide whether to suspend the queue or to immediately requeue.

catch’s picture

So if a similar implementation existed in Drush and you run your queue there, if it doesn't handle the return it would normally delete the item since an exception wasn't thrown. Then the item is lost rather then being completed correct?

This is why I just committed the patch with the 9.x follow-up, couldn't think of a way to handle bc in both directions.

We can add __drupal_queue_api_version to $data passed to processItem and then the worker can decide whether to suspend the queue or to immediately requeue.

That could be an option though yes. It will be extra code everywhere, but allow us to add the new return types then remove the bc stuff later which is all you can ask for.

chx’s picture

> add the new return types

What typeS?

catch’s picture

Theoretical new return types we might add other than this one in the future that aren't errors. For example we might want to distinguish between 'keep my place at the front of the queue' vs. 'send me to the back of the queue'.

chx’s picture

I doubt that's possible. The "yardstick" is the ability to use Amazon SQS as the queue backend.

Anyways, I get what you are saying.

catch’s picture

Right we can't guarantee that a backend supports ordering but I think "don't delete" vs. "recreate" might be fine despite that.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

catch’s picture

Status: Needs review » Fixed

This is already in, so we should open a new issue for any follow-up.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.