diff --git a/.docker/entrypoint.sh b/.docker/entrypoint.sh index 7c24832..7f0b4d2 100644 --- a/.docker/entrypoint.sh +++ b/.docker/entrypoint.sh @@ -116,13 +116,35 @@ export OCTANE_WORKERS OCTANE_TASK_WORKERS OCTANE_MAX_REQUESTS \ echo "[entrypoint] Auto-tune (profile=${RESOURCE_PROFILE}): cpus=${CPUS} mem=${MEM_MIB}MiB slots=${SLOTS} -> octane=${OCTANE_WORKERS} horizon(dp/biz/notif)=${HORIZON_DATA_PIPELINE_MAX}/${HORIZON_BUSINESS_MAX}/${HORIZON_NOTIFICATION_MAX} horizon_worker_mem=${HORIZON_WORKER_MEMORY_MB}MB" echo "[entrypoint] Horizon supervisors use balance=auto with minProcesses=1, so they scale up to the cap on demand and back down when idle." +redis_reachable() { + local host port + host=$(grep -E '^REDIS_HOST=' /www/.env 2>/dev/null | tail -1 | cut -d= -f2- | tr -d '"' | tr -d "'") + port=$(grep -E '^REDIS_PORT=' /www/.env 2>/dev/null | tail -1 | cut -d= -f2- | tr -d '"' | tr -d "'") + command -v redis-cli >/dev/null 2>&1 || return 1 + [ -n "$host" ] || return 1 + case "$host" in + /*) [ -S "$host" ] && redis-cli -s "$host" ping 2>/dev/null | grep -q PONG ;; + *) redis-cli -h "$host" -p "${port:-6379}" ping 2>/dev/null | grep -q PONG ;; + esac +} + if [ ! -s /www/.env ] || ! grep -qE '^INSTALLED=(1|true)$' /www/.env || echo " $* " | grep -q ' xboard:install '; then echo "[entrypoint] Skipping xboard:update (not yet installed or running xboard:install)." else - echo "[entrypoint] Running xboard:update..." - php /www/artisan xboard:update --no-interaction || \ - echo "[entrypoint] WARNING: xboard:update failed; continuing so supervisor can boot anyway." >&2 + if redis_reachable; then + echo "[entrypoint] Running xboard:update (redis reachable, real drivers)..." + php /www/artisan xboard:update --no-interaction || \ + echo "[entrypoint] WARNING: xboard:update failed; continuing so supervisor can boot anyway." >&2 + else + echo "[entrypoint] Running xboard:update (redis not yet up, using array/sync drivers)..." + CACHE_DRIVER=array QUEUE_CONNECTION=sync SESSION_DRIVER=array \ + php /www/artisan xboard:update --no-interaction || \ + echo "[entrypoint] WARNING: xboard:update failed; continuing so supervisor can boot anyway." >&2 + fi fi echo "[entrypoint] Starting services (caddy=${ENABLE_CADDY} web=${ENABLE_WEB} horizon=${ENABLE_HORIZON} ws=${ENABLE_WS_SERVER})..." +# Drop stale Octane/WorkerMan state files so the new master does not signal +# PIDs left over from a previous container run (causes Swoole kill EPERM). +rm -f /www/storage/logs/octane-server-state.json /www/storage/logs/xboard-ws-server.pid 2>/dev/null || true exec "$@" diff --git a/.docker/supervisor/supervisord.conf b/.docker/supervisor/supervisord.conf index 43e45f7..1c3f153 100644 --- a/.docker/supervisor/supervisord.conf +++ b/.docker/supervisor/supervisord.conf @@ -47,6 +47,8 @@ command=redis-server --dir /data --save 900 1 --save 300 10 --save 60 10000 + --bind 127.0.0.1 + --port 6379 --unixsocket /data/redis.sock --unixsocketperm 777 autostart=%(ENV_ENABLE_REDIS)s diff --git a/app/Console/Commands/XboardInstall.php b/app/Console/Commands/XboardInstall.php index a92626e..6e05603 100644 --- a/app/Console/Commands/XboardInstall.php +++ b/app/Console/Commands/XboardInstall.php @@ -101,15 +101,17 @@ class XboardInstall extends Command $isReidsValid = false; while (!$isReidsValid) { // 判断是否为Docker环境 - if ($isDocker == 'true' && ($enableRedis || confirm(label: '是否启用Docker内置的Redis', default: true, yes: '启用', no: '不启用'))) { + $useBuiltinRedis = $isDocker && ($enableRedis || confirm(label: '是否启用Docker内置的Redis', default: true, yes: '启用', no: '不启用')); + if ($useBuiltinRedis) { $envConfig['REDIS_HOST'] = '/data/redis.sock'; $envConfig['REDIS_PORT'] = 0; $envConfig['REDIS_PASSWORD'] = null; - } else { - $envConfig['REDIS_HOST'] = text(label: '请输入Redis地址', default: '127.0.0.1', required: true); - $envConfig['REDIS_PORT'] = text(label: '请输入Redis端口', default: '6379', required: true); - $envConfig['REDIS_PASSWORD'] = text(label: '请输入redis密码(默认: null)', default: ''); + $isReidsValid = true; + break; } + $envConfig['REDIS_HOST'] = text(label: '请输入Redis地址', default: '127.0.0.1', required: true); + $envConfig['REDIS_PORT'] = text(label: '请输入Redis端口', default: '6379', required: true); + $envConfig['REDIS_PASSWORD'] = text(label: '请输入redis密码(默认: null)', default: ''); $redisConfig = [ 'client' => 'phpredis', 'default' => [ @@ -148,6 +150,20 @@ class XboardInstall extends Command $password = Helper::guid(false); $this->saveToEnv($envConfig); + $installDriverOverrides = [ + 'CACHE_DRIVER' => 'array', + 'QUEUE_CONNECTION' => 'sync', + 'SESSION_DRIVER' => 'array', + ]; + foreach ($installDriverOverrides as $key => $value) { + putenv("{$key}={$value}"); + $_ENV[$key] = $value; + $_SERVER[$key] = $value; + } + Config::set('cache.default', 'array'); + Config::set('queue.default', 'sync'); + Config::set('session.driver', 'array'); + $this->call('config:cache'); Artisan::call('cache:clear'); $this->info('正在导入数据库请稍等...'); @@ -170,6 +186,11 @@ class XboardInstall extends Command $this->info("访问 http(s)://你的站点/{$defaultSecurePath} 进入管理面板,你可以在用户中心修改你的密码。"); $envConfig['INSTALLED'] = true; $this->saveToEnv($envConfig); + foreach (array_keys($installDriverOverrides) as $key) { + putenv($key); + unset($_ENV[$key], $_SERVER[$key]); + } + Artisan::call('config:clear'); } catch (\Exception $e) { $this->error($e); } diff --git a/app/Console/Commands/XboardUpdate.php b/app/Console/Commands/XboardUpdate.php index eec1965..2dabec0 100644 --- a/app/Console/Commands/XboardUpdate.php +++ b/app/Console/Commands/XboardUpdate.php @@ -51,10 +51,14 @@ class XboardUpdate extends Command $updateService->updateVersionCache(); $themeService = app(ThemeService::class); $themeService->refreshCurrentTheme(); - try { - Artisan::call('horizon:terminate'); - } catch (\Throwable $e) { - $this->warn('horizon:terminate skipped: ' . $e->getMessage()); + if (config('queue.default') === 'sync') { + $this->info('horizon:terminate skipped (sync queue, no workers to terminate).'); + } else { + try { + Artisan::call('horizon:terminate'); + } catch (\Throwable $e) { + $this->warn('horizon:terminate skipped: ' . $e->getMessage()); + } } $this->info('更新完毕,队列服务已重启,你无需进行任何操作。'); }