Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.x development #126

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,6 @@ jobs:
- { queue: 'github-actions-laravel10-php83', laravel: '10.*', php: '8.3', 'testbench': '8.*'}
- { queue: 'github-actions-laravel10-php82', laravel: '10.*', php: '8.2', 'testbench': '8.*'}
- { queue: 'github-actions-laravel10-php81', laravel: '10.*', php: '8.1', 'testbench': '8.*'}
- { queue: 'github-actions-laravel9-php83', laravel: '9.*', php: '8.3', 'testbench': '7.*'}
- { queue: 'github-actions-laravel9-php82', laravel: '9.*', php: '8.2', 'testbench': '7.*'}
- { queue: 'github-actions-laravel9-php81', laravel: '9.*', php: '8.1', 'testbench': '7.*'}
- { queue: 'github-actions-laravel9-php80', laravel: '9.*', php: '8.0', 'testbench': '7.*'}
- { queue: 'github-actions-laravel8-php81', laravel: '8.*', php: '8.1', 'testbench': '6.*'}
- { queue: 'github-actions-laravel8-php80', laravel: '8.*', php: '8.0', 'testbench': '6.*'}
- { queue: 'github-actions-laravel8-php74', laravel: '8.*', php: '7.4', 'testbench': '6.*'}
- { queue: 'github-actions-laravel7-php80', laravel: '7.*', php: '8.0', 'testbench': '5.*' }
- { queue: 'github-actions-laravel7-php74', laravel: '7.*', php: '7.4', 'testbench': '5.*' }
- { queue: 'github-actions-laravel6-php80', laravel: '6.*', php: '8.0', 'testbench': '4.*' }
- { queue: 'github-actions-laravel6-php74', laravel: '6.*', php: '7.4', 'testbench': '4.*' }

name: PHP ${{ matrix.payload.php }} - Laravel ${{ matrix.payload.laravel }} - DB ${{ matrix.db }}

Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This package allows Google Cloud Tasks to be used as the queue driver.
</summary>

<br>
This package requires Laravel 6 or higher and supports MySQL 8 and PostgreSQL 14. Might support older database versions too, but package hasn't been tested for it.
This package requires Laravel 10 or higher and supports MySQL 8 and PostgreSQL 15. Might support older database versions too, but package hasn't been tested for it.

Please check the [Laravel support policy](https://laravel.com/docs/master/releases#support-policy) table for supported Laravel and PHP versions.
</details>
Expand Down Expand Up @@ -85,8 +85,7 @@ With Cloud Tasks, this is not the case. Instead, Cloud Tasks will schedule the j

#### Good to know

- The "Min backoff" and "Max backoff" options in Cloud Tasks are ignored. This is intentional: Laravel has its own backoff feature (which is more powerful than what Cloud Tasks offers) and therefore I have chosen that over the Cloud Tasks one.
- Similarly to the backoff feature, I have also chosen to let the package do job retries the 'Laravel way'. In Cloud Tasks, when a task throws an exception, Cloud Tasks will decide for itself when to retry the task (based on the backoff values). It will also manage its own state and knows how many times a task has been retried. This is different from Laravel. In typical Laravel queues, when a job throws an exception, the job is deleted and released back onto the queue. In order to support Laravel's backoff feature, this package must behave the same way about job retries.
- Backoff, retries, max tries, retryUntil are all handled by Laravel. All these options are ignored in the Cloud Tasks configuration.

</details>
<details>
Expand Down
21 changes: 3 additions & 18 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
"thecodingmachine/safe": "^1.0|^2.0"
},
"require-dev": {
"orchestra/testbench": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0",
"orchestra/testbench": "^8.0",
"nunomaduro/larastan": "^1.0 || ^2.0",
"thecodingmachine/phpstan-safe-rule": "^1.2",
"laravel/legacy-factories": "^1.3"
"laravel/legacy-factories": "^1.3",
"laravel/pint": "^1.13"
},
"autoload": {
"psr-4": {
Expand All @@ -44,22 +45,6 @@
"l10": [
"composer require laravel/framework:10.* orchestra/testbench:8.* --no-interaction --no-update",
"composer update --prefer-stable --prefer-dist --no-interaction"
],
"l9": [
"composer require laravel/framework:9.* orchestra/testbench:7.* --no-interaction --no-update",
"composer update --prefer-stable --prefer-dist --no-interaction"
],
"l8": [
"composer require laravel/framework:8.* orchestra/testbench:6.* --no-interaction --no-update",
"composer update --prefer-stable --prefer-dist --no-interaction"
],
"l7": [
"composer require laravel/framework:7.* orchestra/testbench:5.* --no-interaction --no-update",
"composer update --prefer-stable --prefer-dist --no-interaction"
],
"l6": [
"composer require laravel/framework:6.* orchestra/testbench:4.* --no-interaction --no-update",
"composer update --prefer-stable --prefer-dist --no-interaction"
]
}
}
2 changes: 1 addition & 1 deletion config/cloud-tasks.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
return [
'dashboard' => [
'enabled' => env('STACKKIT_CLOUD_TASKS_DASHBOARD_ENABLED', false),
'password' => env('STACKKIT_CLOUD_TASKS_DASHBOARD_PASSWORD', 'MyPassword1!')
'password' => env('STACKKIT_CLOUD_TASKS_DASHBOARD_PASSWORD', 'MyPassword1!'),
],
];
2 changes: 1 addition & 1 deletion factories/StackkitCloudTaskFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use Faker\Generator as Faker;
use Illuminate\Support\Str;
use Stackkit\LaravelGoogleCloudTasksQueue\StackkitCloudTask;
use Faker\Generator as Faker;

$factory->define(StackkitCloudTask::class, function (Faker $faker) {
return [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Expand Down
7 changes: 7 additions & 0 deletions pint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"preset": "laravel",
"rules": {
"fully_qualified_strict_types": true,
"declare_strict_types": true
}
}
2 changes: 2 additions & 0 deletions src/Authenticate.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Stackkit\LaravelGoogleCloudTasksQueue;

use Closure;
Expand Down
11 changes: 4 additions & 7 deletions src/CloudTasks.php
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<?php

declare(strict_types=1);

namespace Stackkit\LaravelGoogleCloudTasksQueue;

use Carbon\Carbon;
use Closure;
use Throwable;

final class CloudTasks
Expand All @@ -18,7 +19,7 @@ public static function check($request)
{
$token = $request->bearerToken();

if (!$token) {
if (! $token) {
return false;
}

Expand All @@ -27,14 +28,12 @@ public static function check($request)

return $expireTimestamp > Carbon::now()->timestamp;
} catch (Throwable $e) {
return false;
return false;
}
}

/**
* Determine if the dashboard is enabled.
*
* @return bool
*/
public static function dashboardEnabled(): bool
{
Expand All @@ -43,8 +42,6 @@ public static function dashboardEnabled(): bool

/**
* Determine if the dashboard is disabled.
*
* @return bool
*/
public static function dashboardDisabled(): bool
{
Expand Down
3 changes: 0 additions & 3 deletions src/CloudTasksApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@

namespace Stackkit\LaravelGoogleCloudTasksQueue;

use Google\Cloud\Tasks\V2\RetryConfig;
use Google\Cloud\Tasks\V2\Task;
use Illuminate\Support\Facades\Facade;

/**
* @method static RetryConfig getRetryConfig(string $queueName)
* @method static Task createTask(string $queueName, Task $task)
* @method static void deleteTask(string $taskName)
* @method static Task getTask(string $taskName)
* @method static int|null getRetryUntilTimestamp(Task $task)
*/
class CloudTasksApi extends Facade
{
Expand Down
44 changes: 1 addition & 43 deletions src/CloudTasksApiConcrete.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,13 @@

namespace Stackkit\LaravelGoogleCloudTasksQueue;

use Exception;
use Google\Cloud\Tasks\V2\Attempt;
use Google\Cloud\Tasks\V2\CloudTasksClient;
use Google\Cloud\Tasks\V2\RetryConfig;
use Google\Cloud\Tasks\V2\Task;
use Google\Protobuf\Duration;
use Google\Protobuf\Timestamp;

class CloudTasksApiConcrete implements CloudTasksApiContract
{
/**
* @var CloudTasksClient $client
* @var CloudTasksClient
*/
private $client;

Expand All @@ -24,17 +19,6 @@ public function __construct(CloudTasksClient $client)
$this->client = $client;
}

public function getRetryConfig(string $queueName): RetryConfig
{
$retryConfig = $this->client->getQueue($queueName)->getRetryConfig();

if (! $retryConfig instanceof RetryConfig) {
throw new Exception('Queue does not have a retry config.');
}

return $retryConfig;
}

public function createTask(string $queueName, Task $task): Task
{
return $this->client->createTask($queueName, $task);
Expand All @@ -49,30 +33,4 @@ public function getTask(string $taskName): Task
{
return $this->client->getTask($taskName);
}

public function getRetryUntilTimestamp(Task $task): ?int
{
$attempt = $task->getFirstAttempt();

if (!$attempt instanceof Attempt) {
return null;
}

$queueName = implode('/', array_slice(explode('/', $task->getName()), 0, 6));

$retryConfig = $this->getRetryConfig($queueName);

$maxRetryDuration = $retryConfig->getMaxRetryDuration();
$dispatchTime = $attempt->getDispatchTime();

if (! $maxRetryDuration instanceof Duration || ! $dispatchTime instanceof Timestamp) {
return null;
}

$maxDurationInSeconds = (int) $maxRetryDuration->getSeconds();

$firstAttemptTimestamp = $dispatchTime->toDateTime()->getTimestamp();

return $firstAttemptTimestamp + $maxDurationInSeconds;
}
}
5 changes: 2 additions & 3 deletions src/CloudTasksApiContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@

namespace Stackkit\LaravelGoogleCloudTasksQueue;

use Google\Cloud\Tasks\V2\RetryConfig;
use Google\Cloud\Tasks\V2\Task;

interface CloudTasksApiContract
{
public function getRetryConfig(string $queueName): RetryConfig;
public function createTask(string $queueName, Task $task): Task;

public function deleteTask(string $taskName): void;

public function getTask(string $taskName): Task;
public function getRetryUntilTimestamp(Task $task): ?int;
}
26 changes: 14 additions & 12 deletions src/CloudTasksApiController.php
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
<?php

declare(strict_types=1);

namespace Stackkit\LaravelGoogleCloudTasksQueue;

use const STR_PAD_LEFT;

use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Stackkit\LaravelGoogleCloudTasksQueue\Entities\StatRow;
use const STR_PAD_LEFT;

class CloudTasksApiController
{
public function login(): ?string
{
$password = config('cloud-tasks.dashboard.password');

if (!is_string($password)) {
if (! is_string($password)) {
return null;
}

$validPassword = hash_equals($password, request('password'));

if (!$validPassword) {
if (! $validPassword) {
return null;
}

Expand All @@ -31,9 +34,9 @@ public function login(): ?string

public function dashboard(): array
{
$dbDriver = config('database.connections.' . config('database.default') . '.driver');
$dbDriver = config('database.connections.'.config('database.default').'.driver');

if (!in_array($dbDriver, ['mysql', 'pgsql'])) {
if (! in_array($dbDriver, ['mysql', 'pgsql'])) {
throw new Exception('Unsupported database driver for Cloud Tasks dashboard.');
}

Expand All @@ -59,12 +62,12 @@ public function dashboard(): array
DB::raw('CASE WHEN status = \'failed\' THEN 1 ELSE 0 END AS failed'),
DB::raw('
CASE
WHEN ' . $groupBy['this_minute'] . ' = \'' . now()->utc()->format('H:i') . '\' THEN \'this_minute\'
WHEN ' . $groupBy['this_hour'] . ' = \'' . now()->utc()->format('H') . '\' THEN \'this_hour\'
WHEN '.$groupBy['this_minute'].' = \''.now()->utc()->format('H:i').'\' THEN \'this_minute\'
WHEN '.$groupBy['this_hour'].' = \''.now()->utc()->format('H').'\' THEN \'this_hour\'

ELSE \'today\'
END AS time_preset
')
'),
]
)
->groupBy(
Expand All @@ -74,7 +77,7 @@ public function dashboard(): array
]
)
->get()
->map(fn($row) => StatRow::createFromObject($row))
->map(fn ($row) => StatRow::createFromObject($row))
->toArray();

$response = [
Expand Down Expand Up @@ -156,11 +159,10 @@ public function tasks()

$maxId = $tasks->max('id');

return $tasks->map(function (StackkitCloudTask $task) use ($maxId)
{
return $tasks->map(function (StackkitCloudTask $task) use ($maxId) {
return [
'uuid' => $task->task_uuid,
'id' => str_pad((string) $task->id, strlen($maxId), '0', STR_PAD_LEFT),
'id' => str_pad((string) $task->id, strlen((string) $maxId), '0', STR_PAD_LEFT),
'name' => $task->name,
'status' => $task->status,
'attempts' => $task->getNumberOfAttempts(),
Expand Down
Loading