schmittjoh / JMSJobQueueBundle

Run and Schedule Symfony Console Commands as Background Jobs
http://jmsyst.com/bundles/JMSJobQueueBundle
335 stars 254 forks source link

Delay between retries #59

Closed kingcrunch closed 10 years ago

kingcrunch commented 10 years ago

Maybe this is a duplicate. In that case, of course just close.

It should be possible to set a time to wait for a job to retry. In some cases it doesn't make sense to immediate retry a job. For example

schmittjoh commented 10 years ago

I don't think this is supported right now (at least not intentionally).

I'm also not sure whether we can implement this in a generic way, maybe it's better if you implement this in your application logic for now and don't rely on the automatic retry functionality of this bundle.

kingcrunch commented 10 years ago

That was my first thought too, but that means, that I have to carry around the current retry attempt through every execution and such. I fear, that could get quite messy.

On the other hand: Shouldn't it be fairly easy to set setExecuteAfter() on the retry-job, isn't?

kingcrunch commented 10 years ago

I made a PR out of this. Actually that should be everything needed, shouldn't? It accepts a parseable string like the cleanup job.

schmittjoh commented 10 years ago

If you have a fixed waiting time, I guess this works, but what if you'd like something like exponentially increasing waiting time?

kingcrunch commented 10 years ago

Well... I don't want. That is out of scope of this ticket :cat: While I can imagine, that there are use-cases for exponential-increasing cooldown times (currently I can't, it's late) I'd say it is better to at least support a fixed one. What do you think it should support?

schmittjoh commented 10 years ago

I'm happy to just support a fixed time if we have a plan how further modifications in this area will not create a mess or even better can be done without me making further changes to the bundle :)

kingcrunch commented 10 years ago

oookay, I have an idea. To outline

interface RetrySchedulerInterface {
    punlic function getSchedule(Job $job, Job $retryJob);
}

// for example

class FixCooldownScheduler implements RetrySchedulerInterface {
    protected $cooldown;
    public function __construct ($cooldown)
    {
        $this->cooldown = $cooldown;
    }

    public function schedule (Job $job, Job $retryJob) {
        // $job isn't used here, but other implementations can easily use for example
        // the number of already performed tasks, or the current time (to avoid 
        // huge tasks during rush hour)
        $retryJob->setExecuteAfter(new \DateTime($this->cooldown));
    }
}

class Job {
    /**
     * ORM\Column('type="object")
     */
    protected $retryScheduler = null;

    // ...

    public function scheduleRetryJob (Job $retryJob)
    {
        $this->getRetryScheduler()->schedule($this, $retryJob);
    }
}

// Use

$job->setRetryScheduler(new FixCooldownScheduler('5min'));

// later
$job->scheduleRetryJob($retryJob);

Probably full of errors, but it should illustrate the idea: The use of an object as value (not as assocation) to describe the way retry jobs are scheduled. I'd say now everything is possible :smile: