GithubHelp home page GithubHelp logo

shadowfax's Introduction

English | 中文

Shadowfax

The Shadowfax is a package that runs your Laravel application on Swoole.

Installation

You may use Composer to install Shadowfax to your project:

composer require huang-yi/shadowfax

If you are using Lumen, you need to register the service provider manually in bootstrap/app.php:

$app->register(HuangYi\Shadowfax\ShadowfaxServiceProvider::class);

After installing Shadowfax, publish its configuration files using the shadowfax:publish Artisan command:

php artisan shadowfax:publish

Configuration

The primary configuration file is shadowfax.yml. And this file name is added to the .gitignore file by shadowfax:publish Artisan command.

  1. Basic configuration:
  • name: The processes name.
  • type: The server type, support: http, websocket.
  • host: The server host.
  • port: The server port.
  • mode: The server mode, support: process, base.
  • access_log: Indicates whether to print the request information.
  • app_pool_capacity: Set the capacity of the apps pool. Only valid when coroutine is enabled.
  • framework_bootstrapper: Set Laravel bootstrap file. If you changed Laravel's directory structure, you should modify this value.
  1. server configuration:

This section defines the Swoole\Server configuration. Read the official docs for more information.

  1. abstracts configuration:

This option allows you to set a group of abstracts in the Laravel IoC container. These abstracts will be rebound after each request.

  1. controllers configuration:

This option allows you to clean the controller instances in route after each request.

controllers:
  - App\Http\Controllers\FooController
  - App\Http\Controllers\BarController
  1. cleaners configuration:

This option allows you to register custom cleaners. These cleaners will run after each request.

cleaners:
  - app/Cleaners/
  - CustomNamespace/FooCleaner
  1. db_pools configuration:

This option allows you to configure database connection pools. You can add multiple key-value pairs in here. The key name is a connection name in your database.connections, the key value is the connection pool capacity. e.g.:

db_pools:
  mysql: 3
  mysql2: 5
  1. redis_pools configuration:

This option allows you to configure redis connection pools. You can add multiple key-value pairs in here. The key name is a connection name in your database.redis, the key value is the connection pool capacity. e.g.:

redis_pools:
  default: 3
  1. controller server configuration:

This section defines the controller server configuration. The controller server allows you to stop or reload your Shadowfax.

Command

Shadowfax provides a shadowfax command to manage your server processes. This command is build on the Symfony console component, so you can run php shadowfax list for more information.

You may run the php shadowfax start command to start Shadowfax server. The --watch|-w option can run your Shadowfax in watch mode. In watch mode, the processes will be automatically reloaded when the files under your project change.

You must install the fswatch before using --watch|-w option.

The php shadowfax reload allows you to reload the Shadowfax processes.

The php shadowfax stop allows you to stop the Shadowfax server.

Database Connection Pool

Before using database connection pools, you must enable Swoole coroutine and configure the hook_flags:

server:
  enable_coroutine: true
  hook_flags: SWOOLE_HOOK_ALL

Then, add your connection to the db_pools option, and specify a pool capacity:

db_pools:
  mysql: 3
  mysql2: 5

Redis Connection Pool

The difference with database connection pool is that redis connection pools are configured under the redis_pools option.

redis_pools:
  default: 3

WebSocket Server

Shadowfax also allows you to build your WebSocket server.

First of all, you need to change the value of configuration item type to websocket. Then create a handler class that implemented the HuangYi\Shadowfax\Contracts\WebSocket\Handler interface:

namespace App\WebSocket;

use Illuminate\Http\Request;
use HuangYi\Shadowfax\Contracts\WebSocket\Connection;
use HuangYi\Shadowfax\Contracts\WebSocket\Handler;
use HuangYi\Shadowfax\Contracts\WebSocket\Message;

class EchoServer implements Handler
{
    /**
     * Handler for open event.
     *
     * @param  \HuangYi\Shadowfax\Contracts\WebSocket\Connection  $connection
     * @param  \Illuminate\Http\Request  $request
     * @return mixed
     */
    public function onOpen(Connection $connection, Request $request)
    {
        $connection->send('connected');
    }

    /**
     * Handler for message event.
     *
     * @param  \HuangYi\Shadowfax\Contracts\WebSocket\Connection  $connection
     * @param  \HuangYi\Shadowfax\Contracts\WebSocket\Message  $message
     * @return mixed
     */
    public function onMessage(Connection $connection, Message $message)
    {
        $connection->send($message->getData());
    }

    /**
     * Handler for close event.
     *
     * @param  \HuangYi\Shadowfax\Contracts\WebSocket\Connection  $connection
     * @return mixed
     */
    public function onClose(Connection $connection)
    {
        $connection->send('closed');
    }
}

And bind this handler to a uri in your route file:

use App\WebSocket\EchoServer;
use HuangYi\Shadowfax\Facades\WebSocket;

WebSocket::listen('/echo', new EchoServer);

Now, you can start the WebSocket server by command php shadowfax start.

Nginx Configuration

You may use Nginx as a reverse proxy in production environment:

# Uncomment this if you are running a websocket server.
# map $http_upgrade $connection_upgrade {
#     default upgrade;
#     '' close;
# }

server {
    listen 80;
    server_name example.com;
    root /example.com/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.html index.htm index.php;

    charset utf-8;

    location = /index.php {
        try_files /nonexistent_file @shadowfax;
    }

    location / {
        try_files $uri $uri/ @shadowfax;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 @shadowfax;

    location @shadowfax {
        set $suffix "";

        if ($uri = /index.php) {
            set $suffix ?$query_string;
        }

        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # Uncomment this if you are running a websocket server.
        # proxy_set_header Upgrade $http_upgrade;
        # proxy_set_header Connection $connection_upgrade;

        proxy_pass http://127.0.0.1:1215$suffix;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

You need to add the IP address of the Shadowfax to the App\Http\Middleware\TrustProxies Middleware.

Supervisor Configuration

If you want to use the Supervisor to manage your Shadowfax processes, the following configuration file should suffice:

[program:shadowfax]
process_name=%(program_name)s
directory=/path/to/project
command=php shadowfax start
autostart=true
autorestart=true
user=www
redirect_stderr=true
stdout_logfile=/path/to/project/storage/logs/supervisor.log

Benchmarks

Run tests using wrk.

Environment 1

  • Hardware: 1 CPU, 4 Cores, 16GB Memory
  • MacOS 10.15.3
  • PHP 7.3.12 (with opcache)
  • Swoole 4.4.13
  • Laravel 7 (without session middleware)
  • Shadowfax 2.0.0 (with 20 worker processes)
wrk -t4 -c200 http://127.0.0.1:1215/

Result:

Running 10s test @ http://127.0.0.1:1215/
  4 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    26.44ms   31.44ms 212.73ms   84.28%
    Req/Sec     3.13k   839.99     6.07k    65.75%
  124418 requests in 10.01s, 312.06MB read
  Socket errors: connect 0, read 54, write 0, timeout 0
Requests/sec:  12430.20
Transfer/sec:     31.18MB

Environment 2

  • Hardware: 2 CPUs, 2 Cores, 4GB Memory
  • CentOS 7.5.1804
  • PHP 7.3.16 (with opcache)
  • Swoole 4.4.17
  • Laravel 7 (without session middleware)
  • Shadowfax 2.0.0 (with 10 worker processes)
wrk -c100 http://127.0.0.1:1215/

Result:

Running 10s test @ http://127.0.0.1:1215/
  2 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    25.06ms   12.11ms  85.92ms   60.94%
    Req/Sec     4.02k    41.46     4.08k    79.79%
  40321 requests in 10.08s, 101.13MB read
Requests/sec:   4001.76
Transfer/sec:     10.04MB

Testing

composer test

License

Shadowfax is open-sourced software licensed under the MIT license.

shadowfax's People

Contributors

albertcht avatar huang-yi avatar wilbur-yu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

shadowfax's Issues

Lumen 8 DB:listen 重复记录 sql 日志

QueryLoggerServiceProvider.php

DB::listen(function (QueryExecuted $query) {
	if ($query->time < $this->app['config']->get('logging.query.slower_than', 0)) {
		return;
	}
	
	$sqlWithPlaceholders = str_replace(['%', '?'], ['%%', '%s'], $query->sql);
	
	$bindings = $query->connection->prepareBindings($query->bindings);
	$pdo      = $query->connection->getPdo();
	$realSql  = $sqlWithPlaceholders;
	$duration = $this->formatDuration($query->time / 1000);
	
	if (count($bindings) > 0) {
		$realSql = vsprintf($sqlWithPlaceholders, array_map([$pdo, 'quote'], $bindings));
	}
	
	Log::debug(sprintf('[%s] [%s] %s | %s: %s', $query->connection->getDatabaseName(), $duration, $realSql,
		request()->method(), request()->getRequestUri()));
});

日志

[2020-11-27 23:18:23] local.DEBUG: [test] [500μs] select * from `products` where `products`.`id` = '4' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [500μs] select * from `products` where `products`.`id` = '4' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [500μs] select * from `products` where `products`.`id` = '4' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [500μs] select * from `products` where `products`.`id` = '4' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [500μs] select * from `products` where `products`.`id` = '4' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [500μs] select * from `products` where `products`.`id` = '4' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [500μs] select * from `products` where `products`.`id` = '4' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [500μs] select * from `products` where `products`.`id` = '4' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [500μs] select * from `products` where `products`.`id` = '4' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [500μs] select * from `products` where `products`.`id` = '4' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [390μs] select * from `product_skus` where `product_skus`.`id` = '2' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [390μs] select * from `product_skus` where `product_skus`.`id` = '2' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [390μs] select * from `product_skus` where `product_skus`.`id` = '2' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [390μs] select * from `product_skus` where `product_skus`.`id` = '2' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [390μs] select * from `product_skus` where `product_skus`.`id` = '2' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [390μs] select * from `product_skus` where `product_skus`.`id` = '2' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [390μs] select * from `product_skus` where `product_skus`.`id` = '2' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [390μs] select * from `product_skus` where `product_skus`.`id` = '2' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [390μs] select * from `product_skus` where `product_skus`.`id` = '2' limit 1 | POST: /v1/orders  
[2020-11-27 23:18:23] local.DEBUG: [test] [390μs] select * from `product_skus` where `product_skus`.`id` = '2' limit 1 | POST: /v1/orders  

Laravel Admin 包的一些问题

该包Laravel Admin302 跳转请求不生效,
例如增加菜单项, 提交成功后会进行跳转, 控制台打印到了该请求, 但是没有后续反应

[2020-06-19 16:15:46] 127.0.0.1 [302]: POST http://a.work.test/backend/auth/menu [83.28ms]

数据清理监听器: 按照 Laravel-S

<?php

namespace App\Listeners;

use Encore\Admin\Admin;
use HuangYi\Shadowfax\Events\AppPushingEvent;
use Illuminate\Support\Facades\Facade;

class RebindLaravelAdmin
{
    public const   ADMIN_CLASS = Admin::class;

    protected $properties = [
        'deferredScript' => [],
        'script'         => [],
        'style'          => [],
        'css'            => [],
        'js'             => [],
        'html'           => [],
        'headerJs'       => [],
        'manifestData'   => [],
        'extensions'     => [],
        'minifyIgnores'  => [],
    ];

    /**
     * Handle the event.
     *
     * @param AppPushingEvent $event
     *
     * @return void
     */
    public function handle(AppPushingEvent $event) : void
    {
        $reflection = new \ReflectionClass(self::ADMIN_CLASS);

        foreach ($this->properties as $name => $value) {
            if (property_exists(self::ADMIN_CLASS, $name)) {
                $reflection->setStaticPropertyValue($name, $value);
            }
        }
        $event->app->forgetInstance(self::ADMIN_CLASS);
        Facade::clearResolvedInstance(self::ADMIN_CLASS);
    }
}

Redis连接池不能生效的问题

按照文档配置,然后进行测试,发现大并发下,Redis::get()的时候报错了:Socket#13 has already been bound to another coroutine#1156, reading of the same socket in coroutine#1154 at the same time is not allowed.

跟踪代码后发现,连接池并没有被使用,Redis::get()还是在使用laravel自己的RedisMamager。所以出现了同时使用连接的情况。
然后发现,根本原因是,Laravel自带的RedisServiceProvider,implements了DeferrableProvider,会被滞后加载。

而且,加载时使用了app->singleton,而不是app->singletonIf,所以会直接替换shadowfax注入的RedisMamager。

我临时的解决办法,拷贝Illuminate\Redis\RedisServiceProvider的代码,新建一个自己的RedisServiceProvider,并且把app->singleton改成app->singletonIf,或者去掉implements DeferrableProvider。然后在放入config.app里面。两个方法都可以解决问题,把连接交给连接池分配,实现协程安全。

虽然问题解决了,但总感觉这样操作不太优雅。毕竟,作为一个胶水程序员,我恨不得只用composer就可以做完项目。
我是个Laravel彩笔,不知道有没有什么方法直接在shadowfax里面搞定,而不用新增一个RedisServiceProvider,以及修改config.app

Laravel-Wechat 客服消息接收异常

接入微信后台的客服api
route/api.php

$router->any('wechat/serve', 'WechatMiniCustomerController@serve');

控制器方法

    public function serve() : Response
    {
        $app = $this->getMiniProgram();

        $customerService = $app->customer_service;

        $app->server->push(static function ($message) use ($customerService) {
            if (isset($message['MsgType']) && 'miniprogrampage' === $message['MsgType']) {
                if ('type=map' === $message['PagePath']) {
                    $text = new Text(AirdropConstant::CUSTOMER_INTRO_TEXT);
                    $customerService->message($text)->to($message['FromUserName'])->send();
                }

                $link = new Link(AirdropConstant::APP_INFO[$message['PagePath']]);
                $customerService->message($link)->to($message['FromUserName'])->send();
            }
        });

        return $app->server->serve();
    }

在转发给客服后, 客户端收到消息延迟或者接收不到或者在一段时间后, 会收到好多条.
替换为支持协程的Guzzle Handler后, 也会有这些问题.
PHP-FPM下是正常的.

Controller的构造函数里面使用中间件异常

BaseController.php

class BaseAgentController extends Controller
{
    /**
     * @var $user Collection
     */
    protected $user;

    public function __construct()
    {
        //执行中间件获取用户信息
        $this->middleware(function ($request, $next) {
            $this->user = collect(Auth::user())->except(['permissions', 'roles']);
            return $next($request);
        });
    }

}

IndexController.php

class IndexController extends BaseAgentController
{

    public function index(Request $request)
    {
        $user = $this->user;//这个地方有时能够获取到数据,有的时候不能获取到数据,获取到的是NULL

        return view('admin.index.index', compact('user'));
    }
}

如上在父类的CONTROLLER中的构造函数使用中间件方法给对象属性设置值,在子类的CONTROLLER中有的时候获取不到设置的属性值

Laravel Admin Csv导出功能易现的 MySQL General error 2014 错误

[2020-08-26 15:31:00] production.ERROR: SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active.  Consider using PDOStatement::fetchAll().  Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. (SQL: select * from `points` order by `score` desc, `score` desc limit 100 offset 0) {"exception":"[object] (Illuminate\\Database\\QueryException(code: HY000): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active.  Consider using PDOStatement::fetchAll().  Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. (SQL: select * from `points` order by `score` desc, `score` desc limit 100 offset 0) at /web/project/vendor/laravel/framework/src/Illuminate/Database/Connection.php:671)
[previous exception] [object] (Doctrine\\DBAL\\Driver\\PDOException(code: HY000): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active.  Consider using PDOStatement::fetchAll().  Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. at /web/project/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:66)
[previous exception] [object] (PDOException(code: HY000): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active.  Consider using PDOStatement::fetchAll().  Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. at /web/project/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:64)
[2020-08-26 15:31:08] production.ERROR: swoole exit {"exception":"[object] (Swoole\\ExitException(code: 0): swoole exit at /web/project/vendor/encore/laravel-admin/src/Grid/Exporters/CsvExporter.php:171)

easywechat 网页授权问题

返回回来的 code 一直失效或者二次使用, 导致无法获取用户信息.

log

[2020-10-09 10:14:19] production.ERROR: 获取用户信息失败 {"msg":"Authorize Failed: {\"errcode\":40163,\"errmsg\":\"code been used, hints: [ req_id: GEeEWaMre-GRQona ]\"}"}
[2020-10-09 10:14:20] production.ERROR: 获取用户信息失败 {"msg":"Authorize Failed: {\"errcode\":40029,\"errmsg\":\"invalid code, hints: [ req_id: GEeEUqNre-TL.5ya ]\"}"}

middleware.php

		public function handle(Request $request, Closure $next)
		{
			$session = session(self::SESSION_KEY, []);
//			Log::error('user', ['data' => $session]);
			
			if (!$session) {
				/** @var Application $officialAccount */
				$officialAccount = app('wechat.official_account.wwf');
				
				if ($request->has('code')) {
					try {
						$user = $officialAccount->oauth->user();
						
						// 存储到session
						session([self::SESSION_KEY => $user]);
						
						// 重定向到首页
//						return redirect()->to($this->getTargetUrl($request));
						return redirect()->route('module.wwf.home');
					} catch (AuthorizeFailedException $e) {
						Log::error('获取用户信息失败', ['msg' => $e->getMessage()]);
						
						return redirect()->route('module.wwf.home');
					}
					
				}
				
				session()->forget(self::SESSION_KEY);
				
				return $officialAccount->oauth->scopes(['snsapi_userinfo'])
					->redirect($request->fullUrl());
			}
			
			return $next($request);
		}

文档中Laravel Admin的适配器报错

RT.

// 报错信息
// Uncaught ReflectionException: Class Encore\Admin\Admin does not have a property named extensions in /data/wwwroot/app.xxx/app/Cleaners/EncoreAdminCleaner.php:22
// Uncaught ReflectionException: Class Encore\Admin\Admin does not have a property named html in /data/wwwroot/app.xxx/app/Cleaners/EncoreAdminCleaner.php:22

// 对应代码:
$admin->setStaticPropertyValue($name, $value);

是否应当在请求完成后清除控制器实例?

最近在调研shadowfax技术方案是发现,如果通过Controller的构造函数注入实例属性的话,由于laravel在请求结束后并不会销毁Controller实例,那么即使在设置中设置了abstract字段也不会重新注入。我们有一些简单的解决方案:

  1. 避免在控制器中注入实例。假设我们不打算在shadowfax的行为中对此作出任何改变的话,我们应当在文档中说明,developer不应当在控制器中注入任何可能拥有状态的属性,除非你真的知道你在做什么。
  2. 每次请求完毕后清理控制器,我们有一个简单粗暴的办法来清理每个请求当中生成的控制器:
//HandleRequest.php
//other code
$response->send($event->response);
foreach ($app->routes as $route) {
    unset($route->controller);
}
//other code

这种方案可以让开发者更加无痛集成shadowfax。不过,我们需要评估这种方案对性能的影响,我个人觉得大多数情况下应该没什么太大影响。或者我们可以在配置文件中提供一个选项clear_controller,让用户来自己决定是否需要在请求结束后清理控制器。

RedisManager constructor arguments error

Uncaught TypeError: Argument 2 passed to Illuminate\Redis\RedisManager::__construct() must be of the type array, string given, called in /Users/wangsong/hyperf-skeleton/backend/vendor/huang-yi/shadowfax/src/Laravel/RedisManager.php on line 22 and defined in /U
sers/wangsong/hyperf-skeleton/backend/vendor/laravel/framework/src/Illuminate/Redis/RedisManager.php:41

post 响应状态码 204

作者你好!鄙人现在遇到一个问题,在使用 shadowfax 的端口直接提供服务时,通过浏览器发送 post 请求,会返回 204 状态码(OPTIONS),也没有返回任何内容;但是使用 nginx 转发给 shadowfax 服务,则可以返回 200 状态码和内容。

我在相应的业务代码写了日志,当请求 post 到 shadowfax 的服务端口时,能够完整记录整个执行的过程,但就是没有输出。

系统:alpine 3.12
php: 7.3.27
swoole: 4.6.4-dev
shadowfax: ^2.10

客户端和服务器的域名地址不一样,可能是跨域的问题?如果是,请教一下如何处理?

在使用module形式下, 无法正常加载module定义的provider

现在项目中使用了Laravel Module,
使项目中各功能可以以模块进行划分, 每个模块就是一个服务提供者.
现在的情况是, 在php shadowfax start启动后, 各模块没有加载到provider.

➜ php shadowfax start
Starting the Shadowfax server: 127.0.0.1:1215
[√] master process started. [1624]
[√] manager process started. [1632]
[√] worker process started. [1636]
[√] worker process started. [1637]
[√] worker process started. [1635]
[√] worker process started. [1639]
[√] worker process started. [1634]
[√] worker process started. [1640]
[√] worker process started. [1638]
[√] worker process started. [1633]
[2020-06-17 19:51:12] 127.0.0.1 [404]: POST https://a.work.test/api/mm/signing [36.73ms]
[2020-06-17 19:51:22] 127.0.0.1 [404]: POST https://a.work.test/api/mm/auth/login [1.93ms]

如以上两条路由是由mm模块定义, 但是无法访问到.

是否还没有兼容laravel的文件下载呢?

laravel中response方式:

response()->download
response()->streamDownload

shadowfax源码只是这样处理:

    /**
     * Send the http content.
     *
     * @param  \Swoole\Http\Response  $swooleResponse
     * @return void
     */
    protected function sendContent(SwooleResponse $swooleResponse)
    {
        $swooleResponse->end($this->illuminateResponse->getContent());
    }

而Symfony\Component\HttpFoundation\StreamedResponse中的getContent:

    /**
     * {@inheritdoc}
     */
    public function getContent()
    {
        return false;
    }

如果是StreamedResponse应该调用ob_get_clean()获取内容,然后分段发送才对吧?
Swoole\Http\Response->write(string $data):

LaravelAdmin 表格分页链接问题

线上环境中, 生成的分页链接的 base url 莫名成了我的 api 路由文件中的某个路由.
�如:
api.php

$router->get('user/point', 'Controller@getUserPoint');

laravel-admin 的路由为:

$router->name('mm.')->prefix('mm')->group(static function (Router $router) {
	$router->resource('questions', 'MM\QuestionsController');
	$router->resource('scores', 'MM\ScoresController');
});     

laravel-admin 的页面路径为:

https://xxx.cn/backend/mm/scores

生成的表格分页链接就成了:

https://xxx.cn/api/user/point?page=2
https://xxx.cn/api/user/point?page=3

在本地环境中是生成了:

https://localhost/?page=2
https://localhost/?page=3

非协程模式下Facade调用问题

我参考适配器的代码,加了TymonJwtAuthCleaner;并且在配置中的abstracts加了以下配置:

  • tymon.jwt
  • tymon.jwt.auth
  • tymon.jwt.provider.jwt
  • tymon.jwt.provider.jwt.namshi
  • tymon.jwt.provider.jwt.lcobucci
  • tymon.jwt.provider.auth
  • tymon.jwt.provider.storage
  • tymon.jwt.manager
  • tymon.jwt.blacklist
  • tymon.jwt.payload.factory
  • tymon.jwt.validators.payload

启动服务之后,使用不同用户token获得的用户信息还是同一个。

偶现的崩溃问题

 Whoops\Exception\ErrorException

  Uncaught HuangYi\Shadowfax\Exceptions\EntryNotFoundException: app_pool in /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Container.php:75
Stack trace:
#0 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/helpers.php(23): HuangYi\Shadowfax\Container->make('app_pool')
#1 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/HasHelpers.php(107): shadowfax('app_pool')
#2 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/HasHelpers.php(118): HuangYi\Shadowfax\Listeners\RequestEvent\HandleRequest->appPool()
#3 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/RequestEvent/HandleRequest.php(30): HuangYi\Shadowfax\Listeners\RequestEvent\HandleRequest->handleWithoutException(Object(Closure))
#4 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/EventDispatcher.php(61): HuangYi\Shadowfax\Listeners\RequestEvent\HandleRequest->handle(Object(HuangYi\Shadowfax\Events\RequestEvent))
#5 /Users/wenber/htdocs/w

  at vendor/huang-yi/shadowfax/src/Container.php:75
    71|         if (isset($this->bindings[$abstract])) {
    72|             return $this->instances[$abstract] = $this->bindings[$abstract]($this);
    73|         }
    74|
  > 75|         throw new EntryNotFoundException($abstract);
    76|     }
    77|
    78|     /**
    79|      * Remove a instance from the container.

      +1 vendor frames
  2   [internal]:0
      Whoops\Run::handleShutdown()
[2020-06-25 15:57:08 *23199.1]	ERROR	php_swoole_server_rshutdown (ERRNO 503): Fatal error: Uncaught HuangYi\Shadowfax\Exceptions\EntryNotFoundException: app_pool in /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Container.php:75
Stack trace:
#0 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/helpers.php(23): HuangYi\Shadowfax\Container->make('app_pool')
#1 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/HasHelpers.php(107): shadowfax('app_pool')
#2 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/HasHelpers.php(118): HuangYi\Shadowfax\Listeners\RequestEvent\HandleRequest->appPool()
#3 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/RequestEvent/HandleRequest.php(30): HuangYi\Shadowfax\Listeners\RequestEvent\HandleRequest->handleWithoutException(Object(Closure))
#4 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/EventDispatcher.php(61): HuangYi\Shadowfax\Listeners\RequestEvent\HandleRequest->handle(Object(HuangYi\Shadowfax\Events\RequestEvent))
#5 /Users/wenber/htdocs/w in /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Container.php on line 75
[2020-06-25 15:57:08 $20731.0]	WARNING	swManager_check_exit_status: worker#1[pid=23199] abnormal exit, status=255, signal=0

php shadowfax start -w 起动时, 在修改 .env 文件时, 会偶现这个问题.

wrk 多次压测性能逐渐下降

我又来提问啦, 今天压测api发现, 接口性能多次压测会逐渐下降,
压测接口为 helloWorld 单字符串,
为了重现, 我下载了最新的

  • laravel7.25
  • swoole4.5.2
  • php7.4.9

这是api.php

Route::get('test', function () {
    return 'HelloWorld';
});

这是 shadowfax.yml 配置

name: shadowfax
type: http
host: 127.0.0.1
port: 1215
mode: process
access_log: true
app_pool_capacity: 10

server:
  worker_num: 2
  enable_coroutine: false
...
下面的没有改动

这里列上三次压测结果, (均为连续压测

第一次
Running 10s test @ http://localhost:1215/api/test
  10 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.10s   568.27ms   2.00s    57.44%
    Req/Sec   106.35    109.94     0.89k    87.24%
  4583 requests in 10.03s, 8.28MB read
  Socket errors: connect 0, read 0, write 0, timeout 1888
  Non-2xx or 3xx responses: 4524
Requests/sec:    457.00
Transfer/sec:    845.78KB
第二次
Running 10s test @ http://localhost:1215/api/test
  10 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.00us    0.00us   0.00us    -nan%
    Req/Sec    37.33     32.67   232.00     75.14%
  1425 requests in 10.02s, 2.60MB read
  Socket errors: connect 0, read 0, write 0, timeout 1425
  Non-2xx or 3xx responses: 1425
Requests/sec:    142.23
Transfer/sec:    266.06KB
第三次
Running 10s test @ http://localhost:1215/api/test
  10 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.00us    0.00us   0.00us    -nan%
    Req/Sec    28.96     27.29   150.00     81.82%
  587 requests in 10.02s, 1.07MB read
  Socket errors: connect 0, read 0, write 0, timeout 587
  Non-2xx or 3xx responses: 587
Requests/sec:     58.58
Transfer/sec:    109.61KB

RedisManager 向下兼容问题

HuangYi\Shadowfax\Laravel\RedisManager 中构造方法不适用于 Lumen

public function __construct($app, $driver, array $config, array $poolsConfig = [])
    {
        if (version_compare($app->version(), '5.7', '<')) {
        	echo 1;
            parent::__construct($driver, $config);
        } else {
            parent::__construct($app, $driver, $config);
        }

        $this->poolsConfig = $poolsConfig;
    }

Lumen$app->version() 返回的是:

public function version()
    {
        return 'Lumen (8.2.0) (Laravel Components ^8.0)';
    }

version_compare() 方法无法正确判断. 所以造成在 大于 5.7 版本中的 Lumen 无法正常使用 Redis

[bug]Websocket connect ? worker_num

启用Websocket worker_num为1 , 创建一个websocket链接, 第二个就无法链接,
worker_num = 8 , 则连接8人之后, 就无法继续链接,
不清楚是bug还是机制,我认为应该是bug

第一次尝试这个扩展包

第一次尝试laravel+swoole的项目搭建,第一次使用作者的扩展包,感觉一切好神奇。
自己现在本地的虚拟机跑一段时间,如果没什么问题,尝试搬到线上。
感谢作者!

php shadowfax start 启动报错

php version: 7.4.7
os: macbook pro 10.15.5 (19F101)

[2020-06-17 16:59:16 *93899.7] ERROR php_swoole_server_rshutdown (ERRNO 503): Fatal error: Uncaught ErrorException: array_key_exists() expects parameter 2 to be array, null given in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php:151
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'array_key_exist...', '/Users/wenber/h...', 151, Array)
#1 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(151): array_key_exists('client', NULL)
#2 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(249): Illuminate\Support\Arr::exists(NULL, 'client')
#3 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(487): Illuminate\Support\Arr::forget(NULL, Array)
#4 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/FrameworkBootstrappedEvent/OverrideRedisManager.php(26): Illuminate\Support\Arr::pull(NULL, 'client', 'phpredis')
#5 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/ in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php on line 151
147| if ($array instanceof ArrayAccess) {
148| return $array->offsetExists($key);
149| }
150|

151| return array_key_exists($key, $array);
152| }
153|
154| /**
155| * Return the first element in an array passing a given truth test.
147| if ($array instanceof ArrayAccess) {
148| return $array->offsetExists($key);
149| }
150|
151| return array_key_exists($key, $array);
152| }
153|
154| /**
155| * Return the first element in an array passing a given truth test.

  +1 vendor frames

  +1 vendor frames

2 [internal]:0
Whoops\Run::handleShutdown()
2 [internal]:0
Whoops\Run::handleShutdown()
[2020-06-17 16:59:16 *93904.4] ERROR php_swoole_server_rshutdown (ERRNO 503): Fatal error: Uncaught ErrorException: array_key_exists() expects parameter 2 to be array, null given in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php:151
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'array_key_exist...', '/Users/wenber/h...', 151, Array)
#1 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(151): array_key_exists('client', NULL)
#2 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(249): Illuminate\Support\Arr::exists(NULL, 'client')
#3 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(487): Illuminate\Support\Arr::forget(NULL, Array)
#4 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/FrameworkBootstrappedEvent/OverrideRedisManager.php(26): Illuminate\Support\Arr::pull(NULL, 'client', 'phpredis')
#5 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/ in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php on line 151
[2020-06-17 16:59:16 *93903.2] ERROR php_swoole_server_rshutdown (ERRNO 503): Fatal error: Uncaught ErrorException: array_key_exists() expects parameter 2 to be array, null given in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php:151
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'array_key_exist...', '/Users/wenber/h...', 151, Array)
#1 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(151): array_key_exists('client', NULL)
#2 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(249): Illuminate\Support\Arr::exists(NULL, 'client')
#3 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(487): Illuminate\Support\Arr::forget(NULL, Array)
#4 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/FrameworkBootstrappedEvent/OverrideRedisManager.php(26): Illuminate\Support\Arr::pull(NULL, 'client', 'phpredis')
#5 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/ in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php on line 151

Whoops\Exception\ErrorException

Uncaught ErrorException: array_key_exists() expects parameter 2 to be array, null given in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php:151
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'array_key_exist...', '/Users/wenber/h...', 151, Array)
#1 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(151): array_key_exists('client', NULL)
#2 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(249): Illuminate\Support\Arr::exists(NULL, 'client')
#3 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(487): Illuminate\Support\Arr::forget(NULL, Array)
#4 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/FrameworkBootstrappedEvent/OverrideRedisManager.php(26): Illuminate\Support\Arr::pull(NULL, 'client', 'phpredis')
#5 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/

at vendor/laravel/framework/src/Illuminate/Support/Arr.php:151
147| if ($array instanceof ArrayAccess) {
148| return $array->offsetExists($key);
149| }
150|

151| return array_key_exists($key, $array);
152| }
153|
154| /**
155| * Return the first element in an array passing a given truth test.
PHP Fatal error: Uncaught ErrorException: array_key_exists() expects parameter 2 to be array, null given in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php:151
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'array_key_exist...', '/Users/wenber/h...', 151, Array)
#1 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(151): array_key_exists('client', NULL)
#2 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(249): Illuminate\Support\Arr::exists(NULL, 'client')
#3 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(487): Illuminate\Support\Arr::forget(NULL, Array)
#4 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/FrameworkBootstrappedEvent/OverrideRedisManager.php(26): Illuminate\Support\Arr::pull(NULL, 'client', 'phpredis')
#5 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/ in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php on line 151

  +1 vendor frames

2 [internal]:0
Whoops\Run::handleShutdown()
[2020-06-17 16:59:16 *93905.1] ERROR php_swoole_server_rshutdown (ERRNO 503): Fatal error: Uncaught ErrorException: array_key_exists() expects parameter 2 to be array, null given in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php:151
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'array_key_exist...', '/Users/wenber/h...', 151, Array)
#1 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(151): array_key_exists('client', NULL)
#2 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(249): Illuminate\Support\Arr::exists(NULL, 'client')
#3 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(487): Illuminate\Support\Arr::forget(NULL, Array)
#4 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/FrameworkBootstrappedEvent/OverrideRedisManager.php(26): Illuminate\Support\Arr::pull(NULL, 'client', 'phpredis')
#5 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/ in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php on line 151
[2020-06-17 16:59:16 $93857.0] WARNING swManager_check_exit_status: worker#6[pid=93901] abnormal exit, status=255, signal=0
[2020-06-17 16:59:16 $93857.0] WARNING swManager_check_exit_status: worker#5[pid=93900] abnormal exit, status=255, signal=0
[2020-06-17 16:59:16 $93857.0] WARNING swManager_check_exit_status: worker#7[pid=93899] abnormal exit, status=255, signal=0
[2020-06-17 16:59:16 $93857.0] WARNING swManager_check_exit_status: worker#4[pid=93904] abnormal exit, status=255, signal=0
[2020-06-17 16:59:16 $93857.0] WARNING swManager_check_exit_status: worker#2[pid=93903] abnormal exit, status=255, signal=0

Symfony\Component\ErrorHandler\Error\FatalError

Uncaught ErrorException: array_key_exists() expects parameter 2 to be array, null given in /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php:151
Stack trace:
#0 [internal function]: Illuminate\Foundation\Bootstrap\HandleExceptions->handleError(2, 'array_key_exist...', '/Users/wenber/h...', 151, Array)
#1 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(151): array_key_exists('client', NULL)
#2 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(249): Illuminate\Support\Arr::exists(NULL, 'client')
#3 /Users/wenber/htdocs/work/socialab/vendor/laravel/framework/src/Illuminate/Support/Arr.php(487): Illuminate\Support\Arr::forget(NULL, Array)
#4 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/src/Listeners/FrameworkBootstrappedEvent/OverrideRedisManager.php(26): Illuminate\Support\Arr::pull(NULL, 'client', 'phpredis')
#5 /Users/wenber/htdocs/work/socialab/vendor/huang-yi/shadowfax/

at vendor/laravel/framework/src/Illuminate/Support/Arr.php:151
147| if ($array instanceof ArrayAccess) {
148| return $array->offsetExists($key);
149| }
150|

151| return array_key_exists($key, $array);
152| }
153|
154| /**
155| * Return the first element in an array passing a given truth test.

2.7 版本的 cleaners 机制问题

OS: macOS 10.15.5 (19F101)
PHP: 7.4.7
Laravel: 7.17.1

  1. 文档中指出, 如果使用 shadowfax:cleaners 来生成清理类的话, 无需在 shadowfax.yml 中的 cleaners 进行配置.
    但是我从 2.6 升级后, 将之前的监听器更为清理器时, 生成的清理器目录并未在 shadowfax.yml 自动配置.

  2. 文档中关于对 tymon/jwt-auth 包的清理示例.
    app/Cleaners/TymonJwtAuthCleaner.php

    public function clean(Container $app) : void
    {
        $class    = LaravelServiceProvider::class;
        $provider = new $class;

        $method = (new ReflectionObject($provider))->getMethod('extendAuthGuard');

        $method->setAccessible(true);

        $method->invoke($provider);
    }

启动正常. 请求路由时, 报错如下:

2   [internal]:0
      Whoops\Run::handleShutdown()

   Whoops\Exception\ErrorException

  Uncaught ArgumentCountError: Too few arguments to function Illuminate\Support\ServiceProvider::__construct(), 0 passed in /Users/wilbur/htdocs/work/soci/app/Cleaners/TymonJwtAuthCleaner.php on line 22 and exactly 1 expected in /Users/wilbur/htdocs/work/soci/vendor/laravel/framework/src/Illuminate/Support/ServiceProvider.php:41
Stack trace:
#0 /Users/wilbur/htdocs/work/soci/app/Cleaners/TymonJwtAuthCleaner.php(22): Illuminate\Support\ServiceProvider->__construct()
#1 /Users/wilbur/htdocs/work/soci/vendor/huang-yi/shadowfax/src/Listeners/AppPushingEvent/RunCleaners.php(34): App\Cleaners\TymonJwtAuthCleaner->clean(Object(Illuminate\Foundation\Application))
#2 /Users/wilbur/htdocs/work/soci/vendor/huang-yi/shadowfax/src/EventDispatcher.php(61): HuangYi\Shadowfax\Listeners\AppPushingEvent\RunCleaners->handle(Object(HuangYi\Shadowfax\Events\AppPushingEvent))
#3 /Users/wilbur/htdocs/work/soci/vendor/huang-yi/shadowfax/src/HasEventDispatcher.php(26): HuangYi\Shadowfax\EventDispatcher->dispatch

  at vendor/laravel/framework/src/Illuminate/Support/ServiceProvider.php:41
    37|      *
    38|      * @param  \Illuminate\Contracts\Foundation\Application  $app
    39|      * @return void
    40|      */
  > 41|     public function __construct($app)
    42|     {
    43|         $this->app = $app;
    44|     }
    45|

      +1 vendor frames

WebSocket服务器无法启用协程

当开启协程特性时,由于在Handshake回调中使用defer触发Open事件,此时已经退出协程,所以导致在Open回调中无法使用Swoole\Coroutine\Channel接口。

Lumen 8 使用 Easywechat 组件无法获取 access_token

laravel/lumen-framework: 8.2.1
overtrue/laravel-wechat: 6.0.0
huang-yi/shadowfax: 2.10.3

获取 easywechat 实例

$wechat = app('wechat.mini_program.default')
$wechat->auth->session($code);
// 报错为: access_token null
$wechat = Factory::miniProgram(config('wechat.mini_program.default'));
$wechat->auth->session($code);
// 报错: access_token null

切换为 php-fpm 后, 就正常了. 之前使用 laravel 没有出现这个问题.

--watch 启动异常

PHP 7.3
Swoole 4.5.2

php shadowfax start --watch

显示以下错误,修改文件无法自动重启服务器。fswatch单独运行正常。
PHP Fatal error: Uncaught HuangYi\Watcher\Exceptions\InvalidOutputException: Error: Unknown event type: 414
in /www/wwwroot/pro.yenomcmf.com/vendor/huang-yi/swoole-watcher/src/Commands/Fswatch.php:124
Stack trace:
#0 /www/wwwroot/pro.yenomcmf.com/vendor/huang-yi/shadowfax/src/Console/StartCommand.php(278): HuangYi\Watcher\Commands\Fswatch->parseEvents('Error: Unknown ...')
#1 [internal function]: HuangYi\Shadowfax\Console\StartCommand->HuangYi\Shadowfax\Console{closure}(7)
#2 [internal function]: Swoole\Event::rshutdown()
#3 {main}
thrown in /www/wwwroot/pro.yenomcmf.com/vendor/huang-yi/swoole-watcher/src/Commands/Fswatch.php on line 124

Fatal error: Uncaught HuangYi\Watcher\Exceptions\InvalidOutputException: Error: Unknown event type: 414
in /www/wwwroot/pro.yenomcmf.com/vendor/huang-yi/swoole-watcher/src/Commands/Fswatch.php:124
Stack trace:
#0 /www/wwwroot/pro.yenomcmf.com/vendor/huang-yi/shadowfax/src/Console/StartCommand.php(278): HuangYi\Watcher\Commands\Fswatch->parseEvents('Error: Unknown ...')
#1 [internal function]: HuangYi\Shadowfax\Console\StartCommand->HuangYi\Shadowfax\Console{closure}(7)
#2 [internal function]: Swoole\Event::rshutdown()
#3 {main}
thrown in /www/wwwroot/pro.yenomcmf.com/vendor/huang-yi/swoole-watcher/src/Commands/Fswatch.php on line 124

完整文档的链接打不开

shadowfax.huangyi.tech

ping shadowfax.huangyi.tech
PING shadowfax.huangyi.tech (140.143.228.98): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
^C
--- shadowfax.huangyi.tech ping statistics ---
3 packets transmitted, 0 packets received, 100.0% packet loss

Easywechat 的使用问题

route/api.php

$router->any('wechat', 'WechatController@serve');

Controllers/WechatController.php

    /**
     * @return Response
     * @throws BadRequestException
     * @throws InvalidArgumentException
     * @throws InvalidConfigException
     * @throws ReflectionException
     */
    public function serve()
    {
        $app = Factory::miniProgram(config('mm.mini_program'));

        $app->server->push(static function ($message){
			return "您好!欢迎使用 EasyWeChat";
        });

        return $app->server->serve();
    }

GET 访问 api/wechat 404, 没有异常报错. 无法通过微信的验证请求. PHP-FPM 情况下, 是正常的.

注释 serve() 方法中的代码, 直接返回 response()->json() 是正常.

WARNING swSignalfd_onSignal

刚上线了一个项目, 流量正常
但是在日志中会有以下警告.

	WARNING	swSignalfd_onSignal (ERRNO 707): Unable to find callback function for signal Broken pipe: 13

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.