wip: article AI polish, category SEO fields, cover generator, membership plan seeder
CI / PHPUnit (PHP 8.3) (push) Failing after 4s
CI / PHPUnit (PHP 8.2) (push) Failing after 1m9s
CI / Deploy (manual gate) (push) Skipped

This commit is contained in:
2026-09-07 18:48:37 +00:00
parent 263b98b218
commit 3cec4c5e18
121 changed files with 4701 additions and 313 deletions
+7 -2
View File
@@ -7,7 +7,10 @@ namespace App\Console\Commands;
use Illuminate\Console\Command;
/**
* Simple alternative to workerman:ai for local/dev: drain AI queues once or loop.
* Dev-friendly alternative to `workerman:ai`.
*
* Does NOT start Workerman. It only wraps Laravel's `queue:work` for the
* AI queues so local setups without pcntl/posix/PM2 can still drain jobs.
*/
class QueueAiWorkCommand extends Command
{
@@ -15,10 +18,12 @@ class QueueAiWorkCommand extends Command
{--once : Process available jobs once and exit}
{--max-time=60 : Max seconds when looping}';
protected $description = 'Process ai-content and ai-moderation queues (dev-friendly alternative to workerman:ai)';
protected $description = 'Drain ai-content/ai-moderation via queue:work (does not start Workerman; use workerman:ai for that)';
public function handle(): int
{
$this->comment('queue:ai → Laravel queue:work (not Workerman). For a long-lived Workerman process use: php artisan workerman:ai start');
$params = [
'--queue' => 'ai-content,ai-moderation',
'--tries' => 3,
+39 -7
View File
@@ -10,22 +10,54 @@ use Workerman\Timer;
use Workerman\Worker;
/**
* Long-lived Workerman process for AI queues (content optimize + comment moderation).
* Long-lived Workerman process for AI queues (content polish + comment moderation).
*
* This is separate from `queue:ai`, which is a short-lived Laravel `queue:work`
* helper for local/dev. Production usually runs either this command OR a
* dedicated `queue:work` on the AI queues not both.
*/
class WorkermanAiCommand extends Command
{
protected $signature = 'workerman:ai {--count=1 : Worker processes}';
protected $signature = 'workerman:ai
{action=start : start|stop|restart|reload|status|connections}
{--count=1 : Worker processes}
{--d : Daemonize (pass through to Workerman)}';
protected $description = 'Start Workerman workers that process ai-content and ai-moderation queues';
protected $description = 'Workerman long-running AI queue consumer (ai-content, ai-moderation). Not started by queue:ai.';
public function handle(): int
{
$this->info('Starting Workerman AI runtime (queues: ai-content, ai-moderation)...');
if (! extension_loaded('pcntl') || ! extension_loaded('posix')) {
$this->error('workerman:ai requires the pcntl and posix PHP extensions (Linux/macOS CLI).');
Worker::$pidFile = storage_path('logs/workerman-ai.pid');
Worker::$logFile = storage_path('logs/workerman-ai.log');
return self::FAILURE;
}
$worker = new Worker();
$action = (string) $this->argument('action');
$allowed = ['start', 'stop', 'restart', 'reload', 'status', 'connections'];
if (! in_array($action, $allowed, true)) {
$this->error('Unknown action. Use: '.implode('|', $allowed));
return self::FAILURE;
}
// Workerman treats `artisan` as the start file, so unset paths default
// to the project root (workerman.log / workerman.artisan.status).
$runtime = storage_path('logs');
if (! is_dir($runtime)) {
mkdir($runtime, 0775, true);
}
Worker::$command = $action.($this->option('d') ? ' -d' : '');
Worker::$pidFile = $runtime.'/workerman-ai.pid';
Worker::$logFile = $runtime.'/workerman-ai.log';
Worker::$statusFile = $runtime.'/workerman-ai.status';
Worker::$stdoutFile = $runtime.'/workerman-ai.stdout.log';
$this->info("Workerman AI: {$action} (queues: ai-content, ai-moderation)");
$worker = new Worker;
$worker->count = max(1, (int) $this->option('count'));
$worker->name = 'larablog-ai';