pinguo / php-msf Goto Github PK
View Code? Open in Web Editor NEWPHP微服务框架即Micro Service Framework For PHP
License: GNU General Public License v2.0
PHP微服务框架即Micro Service Framework For PHP
License: GNU General Public License v2.0
Minner.php
public $debug = false;
public function debug($debug = true){
$this->debug = $debug;
return $this;
}
public function go($bindId = null, $sql = null)
{
if ($sql == null) {
$sql = $this->getStatement(false);
}
if($this->debug){
writeln($sql);//打印sql
}
..................
}
最近经常报这个,这是swoole内部的问题,还是msf的?
WARNING swPort_onRead_http: Content-Length is too big, MaxSize=[2088960]. 怎么解决
有没有redirect()跳转函数
文档总是打不开。。 有没有别的地方能看的文档吗?
1、使用alpinelinux 进行重新打 (内核4.x了,但是无论是编译安装swoole 还是通过pcel安装swoole 都回出现找不到 libaio 事事上已经安装了)
2、使用centos7 进行制作(1.1 G )
不是很理解它的价值,因为
class BaseModel extends Model{
public function __constrance(){
echo "BaseModel";
}
}
Controller里getObject(BaseModel::class,);两次,都会打印BaseModel,也就是说,第一次生成的object,第二次还是生成object.
目前渲染的逻辑是当所有目录遍历完之后如果found=false
则会抛出异常:
Lines 265 to 278 in a21350e
但是如果当渲染时出现一些其他的逻辑错误时,比如模版内语法错误/调用的方法不存在等情况时,会在267/268行抛出异常,从而错误的认为是模版没有找到。
解决思路:
在render之前判断模版是否存在,不存在则跳过当前目录。不再在此处捕获异常(Plates内部爆出的异常都是LogicException,无法根据异常类型区分是模版没找到还是其他错误,因此最佳方式就是把模版内的错误直接冒泡出来)。
worker 进程死掉,查看日志,有大量如下记录
WORKER Error {"worker_id":2,"worker_pid":22443,"exit_code":0,"message":null}
貌似一直重启一直死。
根据 swoole 的文档:
$exit_code
退出的状态码,范围是 1 ~255
exit_code 为0,message 为空,咋回事呢?
// swoole server的reactor数量
'reactor_num' => 2,
// swoole server的worker数量
'worker_num' => 4,
// swoole server的task worker数量
'task_worker_num' => 50,
这是我连接线没自动断开吗?导致msf连接数据库超时吗?
/**
* 通过对象池生成对象
*
* @param array $args
* @return \stdClass|mixed
*/
public function getObject(...$args)
{
//请求间隔久时,这里会出现this->context = null的情况。Miner过来的getObject(Mysql::class,...)
return $this->context->getObjectPool()->get(...$args);
}
RPC框架能跨语言调用我觉得是挺重要的,譬如HPROSE就可以跨语言调用
$pool = this->getMysqlPool();
$pool->where('name', 100);
$pool->from($table);
$pool->go();
必现name = 100问题。因为
name改为group,(group为table表的字段)也会报错。
paltes模板可以自定义函数,一般用于一些页面助手函数和挂件,
http://platesphp.com/engine/functions/
但是这些函数里面无法使用 数据库,reids等
在路由定义,和路由的权限上,注解的形式,会大大改善代码的结构和表达/理解
建议补上这个,或给个接口。当然也有了$this->response->end()
看了下整个项目的思路:
收益良多,感谢~
但感觉目前没有服务注册发现&熔断等特性,如果直接写死ip的话,感觉不利于维护和扩展,后面有考虑加上这一块吗?
将目前使用的目标渲染引擎pinguo/plates 修改为官方维护的hephpleague/plates。
替换为官方repo的主要原因是:
另外,根据官方文档关于视图加载策略的描述:
默认情况下框架会根据请求的控制器名和方法名自动加载视图文件,比如:
http://127.0.0.1:8000/Demo/TplView
这样的URL会自动首先加载的视图文件为app/Views/Demo/TplView.php,如果失败,会继续加载php-msf/src/Views/Demo/TplView.php,如果还是失败,则会抛出异常。
即优先加载用户@app/Views目录下视图,然后尝试加载框架目录下视图。
将视图渲染引擎修改为官方repo之后,仍然可以保证以上策略的完美执行且支持更灵活的策略配置。
为了做到这一点,框架需要修改两个地方:
/**
* 视图文件存储路径,您可以指定多个路径以便让框架载入.
* 数组顺序即加载顺序,当然,框架会自动将框架视图目录放在最后resolve.
*
* @var array
*/
public $viewResolvePaths;
/**
* HttpServer constructor.
*/
public function __construct()
{
parent::__construct();
$this->viewResolvePaths = $this->config->get('http_server.view_paths', [
APP_DIR.'/Views'
]);
foreach ($this->viewResolvePaths as $path) {
// check dir exists and so on.
}
// 框架自带的视图目录.
$this->viewResolvePaths[] = $this->MSFSrcDir;
}
$responseBody = null;
$found = false;
foreach (getInstance()->viewResolvePaths as $basePath) {
try {
$template = getInstance()->templateEngine->setDirectory($basePath)->make($view);
$responseBody = $template->render($data);
$found = true;
break;
} catch (\Throwable $e) {
// pass.
}
}
if (!$found) {
throw new Exception("A template named: {$view} was not found in any folder, please check again");
}
$this->end($responseBody);
现在即可正常使用多级渲染和多目录加载策略了。
比如$this->outputView(["data" => "someData"], "path/to/file");
框架会自动加载
/Base/Output.php;296:Call to undefined method swoole_http_response::gzip()
php --ri swoole :报以上错误
swoole
swoole support => enabled
Version => 1.9.23
Author => tianfeng.han[email: [email protected]]
epoll => enabled
eventfd => enabled
timerfd => enabled
signalfd => enabled
cpu affinity => enabled
spinlock => enabled
rwlock => enabled
async redis client => enabled
async http/websocket client => enabled
Linux Native AIO => enabled
pcre => enabled
mutex_timedlock => enabled
pthread_barrier => enabled
futex => enabled
Directive => Local Value => Master Value
swoole.aio_thread_num => 2 => 2
swoole.display_errors => On => On
swoole.use_namespace => Off => Off
swoole.fast_serialize => Off => Off
swoole.unixsock_buffer_size => 8388608 => 8388608
[root@localhost etc]#
Pool.php类的get()//没见到this->getObject(Class, Params);//没见到Params的传值。
$reflector = new \ReflectionClass($poolName);
$obj = $reflector->newInstanceWithoutConstructor();
$obj->__useCount = 0;
$obj->__genTime = time();
$obj->__isContruct = false;
$obj->__DSLevel = Marco::DS_PUBLIC;
建议
msf依赖monolog的2.0dev版本,但我要安装的overtrue/wechat 依赖monolog的release 1.X的版本,通过composer安装overtrue/wechat 时候报错。请问如何解决?
Conclusion: don't install overtrue/wechat 4.0.1
- Conclusion: don't install overtrue/wechat 4.0.0
- Conclusion: don't install overtrue/wechat 4.0.0-beta.4
- Conclusion: don't install overtrue/wechat 4.0.0-beta.3
- Conclusion: don't install overtrue/wechat 4.0.0-beta.2
- Conclusion: don't install overtrue/wechat 4.0.0-beta.1
- Conclusion: don't install overtrue/wechat 4.0.0-alpha.2
- Conclusion: don't install overtrue/wechat 4.0.0-alpha.1
- Conclusion: remove monolog/monolog 2.0.x-dev
- Installation request for overtrue/wechat ~4.0 -> satisfiable by overtrue/wechat[4.0.0, 4.0.0-alpha.1, 4.0.0-alpha.2, 4.0.0-beta.1, 4.0.0-beta.2, 4.0.0-beta.3, 4.0.0-beta.4, 4.0.1, 4.0.10, 4.0.11, 4.0.12, 4.0.13, 4.0.14, 4.0.15, 4.0.16, 4.0.17, 4.0.18, 4.0.19, 4.0.2, 4.0.20, 4.0.21, 4.0.22, 4.0.3, 4.0.4, 4.0.5, 4.0.6, 4.0.7, 4.0.8, 4.0.9, 4.0.x-dev].
- Conclusion: don't install monolog/monolog 2.0.x-dev
- overtrue/wechat 4.0.x-dev requires monolog/monolog ^1.22 -> satisfiable by monolog/monolog[1.22.0, 1.22.1, 1.23.0, 1.x-dev].
- Can only install one of: monolog/monolog[1.22.0, 2.0.x-dev].
- Can only install one of: monolog/monolog[1.22.1, 2.0.x-dev].
- Can only install one of: monolog/monolog[1.23.0, 2.0.x-dev].
- Can only install one of: monolog/monolog[1.x-dev, 2.0.x-dev].
- Installation request for monolog/monolog (locked at 2.0.x-dev) -> satisfiable by monolog/monolog[2.0.x-dev].
很多常用的库都依赖monolog,并且都是release版本,现在不知道该怎么办了,求解。。
src/Pools/CoroutineRedisProxy.php中第194行:
$arguments[2] = $this->generateUniqueKey(2);
按照generateUniqueKey函数定义,第二个参数始终为2,导致以上命令无法正常使用。
1507708689.923708 [0 127.0.0.1:37236] "RPOPLPUSH" "sourceMQS" "2"
class C extends Controller {
public function actionIndex(){
$user = $this->getObject(User::class);//User class
$result = yield $user->login();//这里有throw new LoginFailException();的情况。
$this->outputJson($result);
}
public function onExceptionHandle(\Throwable $e)
{
if($e instanceof LoginFailException){//这里没有catch到上面的异常。
$this->outputJson(['message'=>$e->getMessage()], 401);
return;
}
parent::onExceptionHandle($e);
}
}
当login throw LoginFailException会报如下错:
[2017-10-12 19:46:12 *29162.0] ERROR zm_deactivate_swoole (ERROR 503): Fatal error: Uncaught App\Exceptions\LoginFailException: 账号或密码错误:0,剩除次数:0 in /opt/rondaful-b2c/msf-server/app/Service/User.php:36
Stack trace:
#0 [internal function]: App\Service\User->login('admin1', 'admin', 10)
#1 /opt/rondaful-b2c/msf-server/vendor/pinguo/php-msf/src/Coroutine/Task.php(159): Generator->send(NULL)
#2 /opt/rondaful-b2c/msf-server/vendor/pinguo/php-msf/src/Coroutine/Scheduler.php(99): PG\MSF\Coroutine\Task->run()
#3 /opt/rondaful
[2017-10-12 19:46:12 $29159.0] WARNING swManager_check_exit_status: worker#0 abnormal exit, status=255, signal=0
[2017-10-12 19:46:12] 服务器进程异常退出 WORKER Error {"worker_id":0,"worker_pid":29162,"exit_code":255,"message":null}
class Test extens Controller{
private $server;
public function __construct($controllerName, $methodName){
parent::__construct($controllerName, $methodName);
$this->server = $this->server ?? $this->getObject(Server::class);
}
}
class Server extens Core{
private $mode;
public function __construct(){
$this->model = $this->getObject(MyModel::class);
}
public function destroy()
{
parent::destroy(); // TODO: Change the autogenerated stub
$this->model = null;
echo "destory\n";
}
public function __destruct()
{
echo "__destruct\n";
}
}
多worker时=4,
前4次请求会Test 调用:?? $this->getObject(Server::class);//因为每个worker都会初始一次server
这4次请求是很正常的。
第5次请求时,?? $this->getObject(Server::class);不会调用了。因为private $server被前4次设值了。
导至Server的__construct不会调用到。
那么为什么前4次明明private $server是非public的,而它的Server实例下的destroy会被调用到。
而且__destruct析构函数也调用了。
第五次没有?? $this->getObject(Server::class);,那$server中的$model就不会this->getObject(MyModel::class);//那这时的$model一直是null了。。。
按照 运行代码 一步步来的。
supervisor> status
除了 msf:php-msf-demo RUNNING
之外,还有 nginx RUNNING
,为什么还要启动 Nginx?好奇。
Demo示例项目配置了HTTP索引页,直接浏览器访问http://127.0.0.1:8000
此处展示提示:Api not found controller(Index)
,但 /welcome 是正常的
查看服务日志 $>cat ~/data/msf-php-msf-demo/server.log
此处 Shell 提示:open(/home/worker/data/www/runtime/demo/server.log) failed. Error: No such file or directory[2]
此页面无限重启,加载的一些 .js 文件都是 404。
Line 101 in 716a097
当httpEnable
为false时,调用父类Server::start()
,Server
没有实现start
成员函数,只能调用魔术方法__call
public function __call($name, $arguments)
{
return $this->server->$name(...$arguments);
}
但是,$this->server还没有实例化。
views目录结构如下:
public
----Header.php
----- Footer.php
index
---- Index.php
Header.php具体内容如下:
<title>KoolTubeeew666666666 this is a test</title>Index.php具体内容如下:
layout('Public/Header') ?>重启server.php后,在浏览器上显示结果如下:
<title>KoolTubeeew666666666 this is a test</title>
Index.php中layout下面的内容没执行。
[2017-11-17 11:33:05] 服务器发生严重错误 WORKER Error swoole_mysql::query(): mysql client is waiting response, cannot send new sql query
$mysql = $this->getMysqlPool('master');
$id = yield $mysql->goBegin();
$a = $mysql->insert('a')->set(['a'=>'a'])->go($id);
$b = $mysql->insert('a')->set(['a'=>'a'])->go($id);
$c = yield $a;
$d = yield $b;
yield $mysql->goCommit($id);
[2017-10-19 10:07:48] Worker Number: 1
[2017-10-19 10:07:48] Task Number: 1
服务的注册,治理,降级,熔断等管理,貌似没有啊
protected function outputFile($filename, $headers = [])
{
$output = $this->getContext()->getOutput();
foreach ($headers as $header=>$value){
$output->setHeader($header, $value);
}
$output->response->sendfile($filename);
$output->__isEnd = true;
}
$filename有30m,要传1分钟,这一分钟里,会一直占用这条请求资源吗?
如果worker只有4(4个请求资源),那不就没法正常走其它业务了吗?疑问~~
extends Core能 $this->getConfig()->get($key);
use Mi没有。
情景:两个同步任务,Demo1阻塞1秒,Demo2阻塞2秒。
<?php
/**
* Demo1
*/
namespace App\Tasks;
use \PG\MSF\Tasks\Task;
class Demo1 extends Task
{
public function test()
{
sleep(1);
return 'Demo1 test';
}
}
<?php
/**
* DEMO2
*/
namespace App\Tasks;
use \PG\MSF\Tasks\Task;
class Demo2 extends Task
{
public function test()
{
sleep(2);
return 'Demo2 test';
}
}
<?php
/**
* 控制器调用
*/
namespace App\Controllers;
use PG\MSF\Controllers\Controller;
class Welcome extends Controller
{
public function actionDemo1()
{
// Demo1任务使用break
$this->getObject(\App\Tasks\Demo1::class)->test()->break();
$this->output('demo1 run');
}
public function actionDemo2()
{
// Demo2任务使用yield
$result = yield $this->getObject(\App\Tasks\Demo2::class)->test();
$this->output('demo2 run,result:'.$result);
}
}
<?php
// 测试
$a = file_get_contents("http://192.168.53.10/welcome/demo1");
$b = file_get_contents("http://192.168.53.10/welcome/demo2");
echo "demo1:".$a."<br >"."demo2:".$b;
结果:
demo1:demo1 run
demo2:demo2 run,result:Demo1 test
demo2任务返回值为Demo1的返回值。
目前只能通过url传参数,复杂一些的参数格式就无法支持
swoole_event_add($this->inotifyFd, function ($inotifyFd) use (&$monitorFiles) {
$events = inotify_read($inotifyFd);
$flag = true;
foreach ($events as $ev) {
if (pathinfo($ev['name'], PATHINFO_EXTENSION) != 'php') {
//创建目录添加监听
if ($ev['mask'] == 1073742080) {
$path = $monitorFiles[$ev['wd']] .'/'. $ev['name'];
$wd = inotify_add_watch($inotifyFd, $path, IN_MODIFY | IN_CREATE | IN_IGNORED | IN_DELETE);
$monitorFiles[$wd] = $path;
}
$flag = false;
continue;
}
writeln('RELOAD ' . $monitorFiles[$ev['wd']] .'/'. $ev['name'] . ' update');
}
if ($flag == true) {
$this->MSFServer->server->reload();
}
}, null, SWOOLE_EVENT_READ);
改为
swoole_event_add($this->inotifyFd, function ($inotifyFd) use (&$monitorFiles) {
$events = inotify_read($inotifyFd);
$flag = true;
$changes = [];//record change
foreach ($events as $ev) {
if (pathinfo($ev['name'], PATHINFO_EXTENSION) != 'php') {
//创建目录添加监听
if ($ev['mask'] == 1073742080) {
$path = $monitorFiles[$ev['wd']] .'/'. $ev['name'];
$wd = inotify_add_watch($inotifyFd, $path, IN_MODIFY | IN_CREATE | IN_IGNORED | IN_DELETE);
$monitorFiles[$wd] = $path;
}
$flag = false;
continue;
}
writeln('RELOAD ' . $monitorFiles[$ev['wd']] .'/'. $ev['name'] . ' update');
$changes[$monitorFiles[$ev['wd']] .'/'. $ev['name']] = 'update';
}
if ($flag == true) {
$callback = $this->config->get('reload.callback');//reload callback
if($callback && is_callable($callback)){
$callback($changes);//call back
}
$this->MSFServer->server->reload();
}
}, null, SWOOLE_EVENT_READ);
是否有计划在框架中集成基于PSR-15规范的中间件?目前有没有替代方案实现类似中间件的功能?
onWorkerStart
$poolName = 'master';
$instnce = getInstance();
$activePoolName = $poolName;
$poolName = MysqlAsynPool::ASYN_NAME . $poolName;
$pool = $instnce->getAsynPool($poolName);
if (!$pool) {
$pool = new MysqlAsynPool($instnce->config, $activePoolName);
getInstance()->addAsynPool($poolName, $pool, true);
}
$tables = yield $pool->go(null, 'show create table config_channel');
print_r($tables);
没有打印print_r($tables);
$this->request->post[$index] ?? ''
改为
$this->request->post[$index] ?? null
这样更合适。因为这个值null可以再用 ??
new MysqlAsynPool出来的,这和设计不合理吗?
在MysqlAsynPool实例中this->getContext()一定是null了。
当我使用 yield 创建临时表时,返回结果应该创建成功并且有记录的,但是查询临时表时报错,提示 临时表不存在!
以下示例代码:
{
// 删除临时表
$db = yield $this->getMysqlPool('master');
$tableName = 'tmp_user_info';
$dropSql = 'DROP TABLE IF EXISTS ' . $tableName .';';
yield $db->go(null,$dropSql);
$querySql = "SELECT * FROM user_info WHERE create_at = '1514691308'";
$createTmpTblSql = "CREATE TEMPORARY TABLE {$tableName} ({$querySql}) ;";
$res1 = yield $db->go(null,$createTmpTblSql);
dump($res1);
/* 输出结果
[
'client_id' => 0
'result' => true
'affected_rows' => 8
'insert_id' => 0
]
*/
$res2 = yield $db->select('*')->from($tableName)->limit(1)->go();
dump($res2);
/*
* [mysql]:Table 'demo_user.tmp_user_info' doesn't exist[sql]:SELECT * FROM tmp_user_info LIMIT 1
*/
return $res2;
}`
由于C扩展 php-beanstalk 多年没有维护,且不支持PHP7,故放弃。
目前打算选择采用 pda/pheanstalk 实现。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.