Skip to content

Commit 2c19e92

Browse files
authored
Merge pull request #9 from doppar/master
merged with master
2 parents 52635bd + b4f9bf5 commit 2c19e92

25 files changed

+1779
-249
lines changed

composer.json

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
2-
"name": "doppar/guard",
3-
"description": "A authorization package for doppar framework",
2+
"name": "doppar/queue",
3+
"description": "A lightweight queue management library for the Doppar framework.",
44
"type": "library",
55
"license": "MIT",
66
"support": {
7-
"issues": "https://github.com/doppar/guard/issues",
8-
"source": "https://github.com/doppar/guard"
7+
"issues": "https://github.com/doppar/queue/issues",
8+
"source": "https://github.com/doppar/queue"
99
},
1010
"authors": [
1111
{
@@ -15,16 +15,17 @@
1515
],
1616
"require-dev": {
1717
"mockery/mockery": "^1.6",
18-
"phpunit/phpunit": "^12.1.5"
18+
"phpunit/phpunit": "^12.1.5",
19+
"doppar/framework": "^3.0.0"
1920
},
2021
"autoload": {
2122
"psr-4": {
22-
"Doppar\\Authorizer\\": "src/"
23+
"Doppar\\Queue\\": "src/"
2324
}
2425
},
2526
"autoload-dev": {
2627
"psr-4": {
27-
"Doppar\\Authorizer\\Tests\\": "tests/"
28+
"Doppar\\Queue\\Tests\\": "tests/"
2829
}
2930
},
3031
"extra": {
@@ -33,7 +34,7 @@
3334
},
3435
"doppar": {
3536
"providers": [
36-
"Doppar\\Authorizer\\GuardServiceProvider"
37+
"Doppar\\Queue\\QueueServiceProvider"
3738
]
3839
}
3940
},

phpunit.xml.dist

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<phpunit colors="true">
2+
<phpunit backupGlobals="false" beStrictAboutTestsThatDoNotTestAnything="false" colors="true" processIsolation="false" stopOnError="false" stopOnFailure="false" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
33
<testsuites>
4-
<testsuite name="Unit">
5-
<directory suffix="Test.php">./tests/Unit</directory>
4+
<testsuite name="Doppar Test Suite">
5+
<directory suffix="Test.php">./tests</directory>
66
</testsuite>
77
</testsuites>
88
<php>
9-
<env name="APP_KEY" value="base64:7n/+NIB4i3LQ6+ZbrclxuwyEqG5Uprufs90NJGL2pls="/>
9+
<ini name="date.timezone" value="UTC" />
10+
<ini name="intl.default_locale" value="C.UTF-8" />
11+
<ini name="memory_limit" value="2048M" />
12+
<env name="DB_CONNECTION" value="testing" />
13+
<!--
14+
<env name="REDIS_CLIENT" value="phpredis" />
15+
<env name="REDIS_HOST" value="127.0.0.1" />
16+
<env name="REDIS_PORT" value="6379" />
17+
-->
1018
</php>
1119
</phpunit>

src/Commands/MakeJobCommand.php

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
3+
namespace Doppar\Queue\Commands;
4+
5+
use Phaseolies\Console\Schedule\Command;
6+
7+
class MakeJobCommand extends Command
8+
{
9+
/**
10+
* The name and signature of the console command.
11+
*
12+
* @var string
13+
*/
14+
protected $name = 'make:job {name}';
15+
16+
/**
17+
* The description of the console command.
18+
*
19+
* @var string
20+
*/
21+
protected $description = 'Create a new Job class';
22+
23+
/**
24+
* Execute the console command.
25+
*
26+
* @return int
27+
*/
28+
protected function handle(): int
29+
{
30+
return $this->executeWithTiming(function () {
31+
$name = $this->argument('name');
32+
$parts = explode('/', $name);
33+
$className = array_pop($parts);
34+
35+
// Ensure class name ends with Job
36+
if (!str_ends_with($className, 'Job')) {
37+
$className .= 'Job';
38+
}
39+
40+
$namespace = 'App\\Jobs' . (count($parts) > 0 ? '\\' . implode('\\', $parts) : '');
41+
$filePath = base_path('app/Jobs/' . str_replace('/', DIRECTORY_SEPARATOR, $name) . '.php');
42+
43+
// Check if Job already exists
44+
if (file_exists($filePath)) {
45+
$this->displayError('Job already exists at:');
46+
$this->line('<fg=white>' . str_replace(base_path(), '', $filePath) . '</>');
47+
return Command::FAILURE;
48+
}
49+
50+
// Create directory if needed
51+
$directoryPath = dirname($filePath);
52+
if (!is_dir($directoryPath)) {
53+
mkdir($directoryPath, 0755, true);
54+
}
55+
56+
// Generate and save Job class
57+
$content = $this->generateJobContent($namespace, $className);
58+
file_put_contents($filePath, $content);
59+
60+
$this->displaySuccess('Job created successfully');
61+
$this->line('<fg=yellow>📦 File:</> <fg=white>' . str_replace(base_path(), '', $filePath) . '</>');
62+
$this->newLine();
63+
$this->line('<fg=yellow>⚙️ Class:</> <fg=white>' . $className . '</>');
64+
65+
return Command::SUCCESS;
66+
});
67+
}
68+
69+
/**
70+
* Generate Job class content.
71+
*/
72+
protected function generateJobContent(string $namespace, string $className): string
73+
{
74+
return <<<EOT
75+
<?php
76+
77+
namespace {$namespace};
78+
79+
use Doppar\Queue\Job;
80+
81+
class {$className} extends Job
82+
{
83+
/**
84+
* Execute the job.
85+
*
86+
* @return void
87+
*/
88+
public function handle(): void
89+
{
90+
//
91+
}
92+
93+
/**
94+
* Handle a job failure.
95+
*
96+
* @param \\Throwable \$exception
97+
* @return void
98+
*/
99+
public function failed(\\Throwable \$exception): void
100+
{
101+
//
102+
}
103+
}
104+
105+
EOT;
106+
}
107+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace Doppar\Queue\Commands;
4+
5+
use Phaseolies\Console\Schedule\Command;
6+
use Doppar\Queue\QueueManager;
7+
use Doppar\Queue\Models\FailedJob;
8+
9+
class QueueFailedCommand extends Command
10+
{
11+
/**
12+
* The name of the console command.
13+
*
14+
* @var string
15+
*/
16+
protected $name = 'queue:failed';
17+
18+
/**
19+
* The command description.
20+
*
21+
* @var string
22+
*/
23+
protected $description = 'List all failed jobs';
24+
25+
/**
26+
* Execute the console command
27+
* Example: php pool queue:failed
28+
*
29+
* @return int
30+
*/
31+
protected function handle(): int
32+
{
33+
$failedJobs = FailedJob::orderBy('failed_at', 'desc')->get();
34+
35+
if ($failedJobs->isEmpty()) {
36+
$this->info("No failed jobs found.");
37+
return Command::SUCCESS;
38+
}
39+
40+
// Create table
41+
$table = $this->createTable();
42+
$table->setHeaders(['ID', 'Job', 'Queue', 'Failed At']);
43+
44+
foreach ($failedJobs as $job) {
45+
$payload = $job->payload;
46+
$data = unserialize($payload);
47+
48+
$jobClass = null;
49+
if ($data && isset($data['job']) && is_object($data['job'])) {
50+
$jobClass = get_class($data['job']);
51+
}
52+
53+
$failedAt = date('Y-m-d H:i:s', $job->failed_at);
54+
$table->addRow([
55+
$job->id,
56+
$jobClass,
57+
$job->queue,
58+
$failedAt
59+
]);
60+
}
61+
62+
// Render table
63+
$table->render();
64+
65+
return Command::SUCCESS;
66+
}
67+
}

src/Commands/QueueFlushCommand.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace Doppar\Queue\Commands;
4+
5+
use Phaseolies\Console\Schedule\Command;
6+
use Doppar\Queue\QueueManager;
7+
use Doppar\Queue\Models\FailedJob;
8+
9+
class QueueFlushCommand extends Command
10+
{
11+
/**
12+
* The name of the console command.
13+
*
14+
* @var string
15+
*/
16+
protected $name = 'queue:flush {--id=}';
17+
18+
/**
19+
* The command description.
20+
*
21+
* @var string
22+
*/
23+
protected $description = 'Delete failed job(s) by ID or all if no ID is provided';
24+
25+
/**
26+
* Execute the console command
27+
* Example: php pool queue:flush --id=1
28+
*
29+
* @return int
30+
*/
31+
protected function handle(): int
32+
{
33+
$id = $this->option('id');
34+
35+
if ($id) {
36+
return $this->flushJobById($id);
37+
}
38+
39+
FailedJob::query()
40+
->cursor(function (FailedJob $failedJob) {
41+
$failedJob->delete();
42+
$this->info("✔ Job with ID {$failedJob->id} has been deleted.");
43+
});
44+
45+
return Command::SUCCESS;
46+
}
47+
48+
protected function flushJobById(int $id): int
49+
{
50+
$failedJob = FailedJob::find($id);
51+
52+
if (!$failedJob) {
53+
$this->error("Failed job with ID {$id} not found.");
54+
return Command::FAILURE;
55+
}
56+
57+
$failedJob->delete();
58+
$this->info("✔ Job with ID {$failedJob->id} has been deleted.");
59+
60+
return Command::SUCCESS;
61+
}
62+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace Doppar\Queue\Commands;
4+
5+
use Phaseolies\Console\Schedule\Command;
6+
use Doppar\Queue\Models\QueueJob;
7+
use Doppar\Queue\Models\FailedJob;
8+
9+
class QueueMonitorCommand extends Command
10+
{
11+
/**
12+
* The name and signature of the console command.
13+
*
14+
* @var string
15+
*/
16+
protected $name = 'queue:monitor';
17+
18+
/**
19+
* The description of the console command.
20+
*
21+
* @var string
22+
*/
23+
protected $description = 'Monitor queue statistics';
24+
25+
/**
26+
* Execute the console command.
27+
*
28+
* @return int
29+
*/
30+
protected function handle(): int
31+
{
32+
$queues = QueueJob::groupBy('queue')->pluck('queue');
33+
34+
// Create table for queue statistics
35+
$table = $this->createTable();
36+
$table->setHeaders(['Queue', 'Pending', 'Processing']);
37+
38+
foreach ($queues ?? [] as $queue) {
39+
$pending = QueueJob::where('queue', $queue)
40+
->whereNull('reserved_at')
41+
->count();
42+
43+
$processing = QueueJob::where('queue', $queue)
44+
->whereNotNull('reserved_at')
45+
->count();
46+
47+
$table->addRow([
48+
$queue,
49+
$pending,
50+
$processing,
51+
]);
52+
}
53+
54+
// Render queue table
55+
$this->newLine();
56+
$this->info("Queue Statistics");
57+
$table->render();
58+
59+
// Failed jobs table
60+
$failedCount = FailedJob::count();
61+
62+
$failedTable = $this->createTable();
63+
$failedTable->setHeaders(['Metric', 'Value']);
64+
$failedTable->addRow(['Failed Jobs', $failedCount]);
65+
66+
$this->info("\nFailed Jobs Summary");
67+
$failedTable->render();
68+
69+
return Command::SUCCESS;
70+
}
71+
}

0 commit comments

Comments
 (0)