From a364d857b4c46dd4a6f8ae7198e10a5039efe0bb Mon Sep 17 00:00:00 2001 From: WuYongJie <549727955@qq.com> Date: Wed, 22 Jul 2026 16:12:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E9=9A=94=E7=A6=BB?= =?UTF-8?q?=E4=B8=8A=E6=B8=B8=E6=95=B0=E6=8D=AE=E5=BA=93=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E6=8E=A2=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/UpstreamOdbcConnection.php | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/modules/EcommerceFinance/Services/UpstreamOdbcConnection.php b/modules/EcommerceFinance/Services/UpstreamOdbcConnection.php index d5c05cfd..dc454cf7 100644 --- a/modules/EcommerceFinance/Services/UpstreamOdbcConnection.php +++ b/modules/EcommerceFinance/Services/UpstreamOdbcConnection.php @@ -6,6 +6,8 @@ use Illuminate\Support\Facades\Log; use PDO; use PDOException; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; +use Symfony\Component\Process\PhpExecutableFinder; +use Symfony\Component\Process\Process; /** * 按来源隔离的 SQL Server PDO_ODBC 连接管理。 @@ -41,6 +43,67 @@ class UpstreamOdbcConnection } public static function probeConfiguration(array $connection, string $label, string $source = 'custom'): void + { + try { + $payload = json_encode([ + 'connection' => $connection, + 'label' => $label, + 'source' => $source, + ], JSON_THROW_ON_ERROR); + $php = (new PhpExecutableFinder())->find(false); + + if (! is_string($php) || $php === '') { + throw new \RuntimeException('PHP CLI 不可用。'); + } + + $script = <<<'PHP' +require getcwd() . '/vendor/autoload.php'; +$app = require getcwd() . '/bootstrap/app.php'; +$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class); +$kernel->bootstrap(); +$payload = json_decode(stream_get_contents(STDIN), true, 512, JSON_THROW_ON_ERROR); +Modules\EcommerceFinance\Services\UpstreamOdbcConnection::probeConfigurationInProcess( + (array) $payload['connection'], + (string) $payload['label'], + (string) $payload['source'], +); +PHP; + $connectTimeout = min(max((int) ($connection['connect_timeout'] ?? 5), 1), 30); + $process = new Process( + [$php, '-d', 'display_errors=0', '-r', $script], + base_path(), + null, + $payload, + min(max($connectTimeout + 3, 5), 15), + ); + $process->run(); + + if ($process->isSuccessful()) { + return; + } + + Log::warning('上游数据库隔离探测失败。', [ + 'source' => $source, + 'source_label' => $label, + 'exit_code' => $process->getExitCode(), + ]); + } catch (\Throwable $exception) { + Log::warning('上游数据库隔离探测无法完成。', [ + 'source' => $source, + 'source_label' => $label, + 'exception' => $exception::class, + ]); + } + + throw new ServiceUnavailableHttpException(60, '上游数据库连接探测失败,请检查配置。'); + } + + /** + * 仅由隔离的 PHP CLI 子进程调用,避免 ODBC 原生崩溃拖垮 Web 请求进程。 + * + * @internal + */ + public static function probeConfigurationInProcess(array $connection, string $label, string $source = 'custom'): void { $pdo = self::open($connection, $source, $label);