Skip to content

Commit 6a65217

Browse files
Merge pull request #38 from stackkit/bugfix/unlimited-max-attempts
Add support for 'Max retry duration' and allow for unlimited tasks
2 parents 45dd325 + 9fd1a36 commit 6a65217

File tree

4 files changed

+386
-18
lines changed

4 files changed

+386
-18
lines changed

src/CloudTasksJob.php

+33-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Stackkit\LaravelGoogleCloudTasksQueue;
44

5+
use Google\Cloud\Tasks\V2\CloudTasksClient;
56
use Illuminate\Container\Container;
67
use Illuminate\Queue\Jobs\Job as LaravelJob;
78
use Illuminate\Contracts\Queue\Job as JobContract;
@@ -11,11 +12,18 @@ class CloudTasksJob extends LaravelJob implements JobContract
1112
private $job;
1213
private $attempts;
1314
private $maxTries;
15+
public $retryUntil = null;
1416

15-
public function __construct($job)
17+
/**
18+
* @var CloudTasksQueue
19+
*/
20+
private $cloudTasksQueue;
21+
22+
public function __construct($job, CloudTasksQueue $cloudTasksQueue)
1623
{
1724
$this->job = $job;
1825
$this->container = Container::getInstance();
26+
$this->cloudTasksQueue = $cloudTasksQueue;
1927
}
2028

2129
public function getJobId()
@@ -41,7 +49,7 @@ public function setAttempts($attempts)
4149
public function setMaxTries($maxTries)
4250
{
4351
if ((int) $maxTries === -1) {
44-
$maxTries = null;
52+
$maxTries = 0;
4553
}
4654

4755
$this->maxTries = $maxTries;
@@ -56,4 +64,27 @@ public function setQueue($queue)
5664
{
5765
$this->queue = $queue;
5866
}
67+
68+
public function setRetryUntil($retryUntil)
69+
{
70+
$this->retryUntil = $retryUntil;
71+
}
72+
73+
public function retryUntil()
74+
{
75+
return $this->retryUntil;
76+
}
77+
78+
// timeoutAt was renamed to retryUntil in 8.x but we still support this.
79+
public function timeoutAt()
80+
{
81+
return $this->retryUntil;
82+
}
83+
84+
public function delete()
85+
{
86+
parent::delete();
87+
88+
$this->cloudTasksQueue->delete($this);
89+
}
5990
}

src/CloudTasksQueue.php

+14
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,20 @@ private function createHttpRequest()
9494
return app(HttpRequest::class);
9595
}
9696

97+
public function delete(CloudTasksJob $job)
98+
{
99+
$config = $this->config;
100+
101+
$taskName = $this->client->taskName(
102+
$config['project'],
103+
$config['location'],
104+
$job->getQueue(),
105+
request()->header('X-Cloudtasks-Taskname')
106+
);
107+
108+
$this->client->deleteTask($taskName);
109+
}
110+
97111
/**
98112
* @return Task
99113
*/

src/TaskHandler.php

+61-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace Stackkit\LaravelGoogleCloudTasksQueue;
44

5+
use Google\Cloud\Tasks\V2\Attempt;
56
use Google\Cloud\Tasks\V2\CloudTasksClient;
7+
use Google\Cloud\Tasks\V2\RetryConfig;
68
use Illuminate\Http\Request;
79
use Illuminate\Queue\Events\JobFailed;
810
use Illuminate\Queue\Worker;
@@ -14,6 +16,16 @@ class TaskHandler
1416
private $publicKey;
1517
private $config;
1618

19+
/**
20+
* @var CloudTasksQueue
21+
*/
22+
private $queue;
23+
24+
/**
25+
* @var RetryConfig
26+
*/
27+
private $retryConfig = null;
28+
1729
public function __construct(CloudTasksClient $client, Request $request, OpenIdVerificator $publicKey)
1830
{
1931
$this->client = $client;
@@ -31,6 +43,8 @@ public function handle($task = null)
3143

3244
$this->loadQueueConnectionConfiguration($task);
3345

46+
$this->setQueue();
47+
3448
$this->authorizeRequest();
3549

3650
$this->listenForEvents();
@@ -48,6 +62,11 @@ private function loadQueueConnectionConfiguration($task)
4862
);
4963
}
5064

65+
private function setQueue()
66+
{
67+
$this->queue = new CloudTasksQueue($this->config, $this->client);
68+
}
69+
5170
/**
5271
* @throws CloudTasksException
5372
*/
@@ -122,29 +141,63 @@ private function listenForEvents()
122141
*/
123142
private function handleTask($task)
124143
{
125-
$job = new CloudTasksJob($task);
144+
$job = new CloudTasksJob($task, $this->queue);
145+
146+
$this->loadQueueRetryConfig();
126147

127148
$job->setAttempts(request()->header('X-CloudTasks-TaskRetryCount') + 1);
128149
$job->setQueue(request()->header('X-Cloudtasks-Queuename'));
129-
$job->setMaxTries($this->getQueueMaxTries($job));
150+
$job->setMaxTries($this->retryConfig->getMaxAttempts());
151+
152+
// If the job is being attempted again we also check if a
153+
// max retry duration has been set. If that duration
154+
// has passed, it should stop trying altogether.
155+
if ($job->attempts() > 1) {
156+
$job->setRetryUntil($this->getRetryUntilTimestamp($job));
157+
}
130158

131159
$worker = $this->getQueueWorker();
132160

133161
$worker->process($this->config['connection'], $job, new WorkerOptions());
134162
}
135163

136-
private function getQueueMaxTries(CloudTasksJob $job)
164+
private function loadQueueRetryConfig()
137165
{
138166
$queueName = $this->client->queueName(
139167
$this->config['project'],
140168
$this->config['location'],
141-
$job->getQueue()
169+
request()->header('X-Cloudtasks-Queuename')
142170
);
143171

144-
return $this->client
145-
->getQueue($queueName)
146-
->getRetryConfig()
147-
->getMaxAttempts();
172+
$this->retryConfig = $this->client->getQueue($queueName)->getRetryConfig();
173+
}
174+
175+
private function getRetryUntilTimestamp(CloudTasksJob $job)
176+
{
177+
$task = $this->client->getTask(
178+
$this->client->taskName(
179+
$this->config['project'],
180+
$this->config['location'],
181+
$job->getQueue(),
182+
request()->header('X-Cloudtasks-Taskname')
183+
)
184+
);
185+
186+
$attempt = $task->getFirstAttempt();
187+
188+
if (!$attempt instanceof Attempt) {
189+
return null;
190+
}
191+
192+
if (! $this->retryConfig->hasMaxRetryDuration()) {
193+
return null;
194+
}
195+
196+
$maxDurationInSeconds = $this->retryConfig->getMaxRetryDuration()->getSeconds();
197+
198+
$firstAttemptTimestamp = $attempt->getDispatchTime()->toDateTime()->getTimestamp();
199+
200+
return $firstAttemptTimestamp + $maxDurationInSeconds;
148201
}
149202

150203
/**

0 commit comments

Comments
 (0)