程序使用的 workerman/gateway-worker。
因?yàn)闃I(yè)務(wù)端需要大量調(diào)用 第三方接口,所以需要使用異步http。
最開始用的 workerman/http-client。 但是第三方接口兼容有問題,每幾百個(gè)請(qǐng)求就有一個(gè)超時(shí)的。
最終經(jīng)過反復(fù)對(duì)比,打算用 Swoole 的攜程調(diào)用 curl 請(qǐng)求第三方接口。
然后再 App.php 添加了 // 使用Swoole事件循環(huán) 利用攜程發(fā)送異步請(qǐng)求
Worker::$eventLoopClass = \Workerman\Events\Swoole::class;
之后啟動(dòng)后,終端包參數(shù)不兼容。
這個(gè)錯(cuò)誤本身問題不大, 主要錯(cuò)誤如下 就是參數(shù)問題。
手動(dòng)修補(bǔ) 可以完美運(yùn)行,但是這樣只是臨時(shí)解決方案。
請(qǐng)問有其他辦法處理此錯(cuò)誤嗎?
TypeError: Workerman\Connection\TcpConnection::__construct(): Argument #3 ($remoteAddress) must be of type string, null given, called in /Users/wheng/phpDevelopment/UtalkLearn/vendor/workerman/workerman/src/Worker.php on line 2638 and defined in /Users/wheng/phpDevelopment/UtalkLearn/vendor/workerman/workerman/src/Connection/TcpConnection.php:369
{
"name": "wheng/utalk-learn",
"type": "project",
"require": {
"workerman/gateway-worker": "v4.0.0",
"symfony/yaml": "^6.3",
"php-amqplib/php-amqplib": "^3.6",
"predis/predis": "^2.2",
"overtrue/pinyin": "^5.3",
"google/protobuf": "^4.27",
"workerman/http-client": "^v3.0.3"
},
"autoload": {
"classmap": [
"src/model/"
],
"psr-4": {
"Proto\\Binarydata\\": "src/Proto/Binarydata/",
"GPBMetadata\\Src\\Protobuf\\": "src/GPBMetadata/Src/Protobuf/"
}
},
"repositories": [
{
"type": "composer",
"url": "https://mirrors.cloud.tencent.com/composer/"
}
],
"config": {
"audit": {
"abandoned": "report"
}
}
}
<?php
/**
* run with command
* php start.php start
*/
date_default_timezone_set('Asia/Shanghai');
ini_set('display_errors', 'on');
use Workerman\Worker;
if (strpos(strtolower(PHP_OS), 'win') === 0) {
exit("start.php not support windows, please use start_for_win.bat\n");
}
// 檢查擴(kuò)展
if (!extension_loaded('pcntl')) {
exit("Please install pcntl extension. See http://doc3.workerman.net/appendices/install-extension.html\n");
}
if (!extension_loaded('posix')) {
exit("Please install posix extension. See http://doc3.workerman.net/appendices/install-extension.html\n");
}
// 標(biāo)記是全局啟動(dòng)
define('GLOBAL_START', 1);
require_once __DIR__ . '/../vendor/autoload.php';
// 加載所有Applications/*/start.php,以便啟動(dòng)所有服務(wù)
foreach (glob(__DIR__ . '/start*.php') as $start_file) {
require_once $start_file;
}
// 使用Swoole事件循環(huán) 利用攜程發(fā)送異步請(qǐng)求
Worker::$eventLoopClass = \Workerman\Events\Swoole::class;
// 運(yùn)行所有服務(wù)
Worker::runAll();
<?php
declare(strict_types=1);
class AsyncExecutorClass
{
/**
* 執(zhí)行異步任務(wù)
* @param callable $task 任務(wù)邏輯
* @param callable $callback 回調(diào)函數(shù) function($result, $error)
* @param mixed ...$args 任務(wù)參數(shù)
*/
public static function run(callable $task, callable $callback, ...$args): void
{
\Workerman\Coroutine::create(function () use ($task, $callback, $args) {
try {
$result = $task(...$args);
$callback($result, null);
} catch (\Throwable $e) {
$callback(null, $e);
}
});
}
}
(base) wheng@MacBook-Pro src % php App.php start
Workerman[App.php] start in DEBUG mode
-------------------------------------------------- WORKERMAN --------------------------------------------------
Workerman/5.1.1 PHP/8.1.32 (Jit off) Darwin/22.6.0
--------------------------------------------------- WORKERS ---------------------------------------------------
event-loop proto user worker listen count state
swoole tcp wheng BusinessWorker none 1 [OK]
swoole tcp wheng Gateway websocket://0.0.0.0:8383 2 [OK]
swoole tcp wheng Register text://0.0.0.0:2238 1 [OK]
---------------------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.
TypeError: Workerman\Connection\TcpConnection::__construct(): Argument #3 ($remoteAddress) must be of type string, null given, called in /Users/wheng/phpDevelopment/UtalkLearn/vendor/workerman/workerman/src/Worker.php on line 2638 and defined in /Users/wheng/phpDevelopment/UtalkLearn/vendor/workerman/workerman/src/Connection/TcpConnection.php:369
Stack trace:
#0 /Users/wheng/phpDevelopment/UtalkLearn/vendor/workerman/workerman/src/Worker.php(2638): Workerman\Connection\TcpConnection->__construct(Object(Workerman\Events\Swoole), Resource id #50, NULL)
#1 /Users/wheng/phpDevelopment/UtalkLearn/vendor/workerman/workerman/src/Events/Swoole.php(288): Workerman\Worker->acceptTcpConnection(Resource id #45)
#2 [internal function]: Workerman\Events\Swoole->Workerman\Events\{closure}()
#3 {main}
if ($remoteAddress === null) {
$remoteAddress = stream_socket_get_name($newSocket, true);
}
可以使用 stream_socket_get_name 二次 獲得這個(gè) 鏈接名字。。
能看得出來(lái), 是 start_gateway.php 沒有為 Swoole 提供兼容支持??!
我最初是頭痛醫(yī)頭腳痛醫(yī)腳, 在 TcpConnection 添加如下代碼
if ($remoteAddress === null) {
$remoteAddress = stream_socket_get_name($newSocket, true);
}
添加兼容代碼后,業(yè)務(wù)能跑起來(lái), 但是偶爾還是報(bào)錯(cuò)!主要是 gateway 通信不暢。
看了 github 上一位仁兄的解決方案后,得到靈感。
在 start_gateway.php 添加代碼如下
$gateway->onConnect = function ($connection) {
// echo "網(wǎng)關(guān)發(fā)生鏈接 client connected\n";
$connection->onWebSocketConnect = function ($connection, $http_header) {};
};
$gateway->eventLoop = \Workerman\Events\Select::class;
// 如果不是在根目錄啟動(dòng),則運(yùn)行runAll方法
if (!defined('GLOBAL_START')) {
Worker::runAll();
}
項(xiàng)目正常運(yùn)轉(zhuǎn)了。。。
(base) wheng@MacBook-Pro src % php App.php start
Workerman[App.php] start in DEBUG mode
-------------------------------------------------- WORKERMAN --------------------------------------------------
Workerman/5.1.1 PHP/8.1.32 (Jit off) Darwin/22.6.0
--------------------------------------------------- WORKERS ---------------------------------------------------
event-loop proto user worker listen count state
swoole tcp wheng BusinessWorker none 1 [OK]
select tcp wheng Gateway websocket://0.0.0.0:8383 1 [OK]
swoole tcp wheng Register text://0.0.0.0:2238 1 [OK]
---------------------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.
gatewayWorker不支持協(xié)程,目前沒有計(jì)劃讓gatewayWorker支持協(xié)程,主要是沒有精力和動(dòng)力。
原因:
$_SESSION
$_SERVER
,這些在協(xié)程中會(huì)造成變量污染問題,需要花很多精力重構(gòu)。不過可以把業(yè)務(wù)都轉(zhuǎn)移到webman來(lái)做,在webman里使用協(xié)程,gatewayWorker只做通訊。