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
+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';