记一次使用 Laravel Http Client 使用不当导致内存泄漏的问题 作者: Chuwen 时间: 2023-12-06 分类: PHP 评论 ## 背景 Laravel 的[ HTTP Client](https://laravel.com/docs/10.x/http-client " HTTP Client") 基于 Guzzle 二次封装,操作很方便,所以在业务代码上我就这么写了类似的代码 ```php $url = 'https://xxxx/xxx.json'; $json = Illuminate\Support\Facades\Http::get($url)->json(); // TODO 业务逻辑处理 ``` 项目使用了 [laravels](https://github.com/hhxsv5/laravel-s "laravels"),所以项目是常驻内存的,但是经过观察发 worker 内存会随着请求数量慢慢增加,并且不会自动回收内存,导致最终内存不足程序异常终止: ``` PHP Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 360448 bytes) in /Users/shine/work/xxxxxx-project/vendor/guzzlehttp/psr7/src/Utils.php on line 414 Symfony\Component\ErrorHandler\Error\FatalError Allowed memory size of 67108864 bytes exhausted (tried to allocate 360448 bytes) at vendor/guzzlehttp/psr7/src/Utils.php:414 410▕ }); 411▕ 412▕ try { 413▕ /** @var string|false $contents */ ➜ 414▕ $contents = stream_get_contents($stream); 415▕ 416▕ if ($contents === false) { 417▕ $ex = new \RuntimeException('Unable to read stream contents'); 418▕ } Whoops\Exception\ErrorException Allowed memory size of 67108864 bytes exhausted (tried to allocate 360448 bytes) at vendor/guzzlehttp/psr7/src/Utils.php:414 410▕ }); 411▕ 412▕ try { 413▕ /** @var string|false $contents */ ➜ 414▕ $contents = stream_get_contents($stream); 415▕ 416▕ if ($contents === false) { 417▕ $ex = new \RuntimeException('Unable to read stream contents'); 418▕ } +1 vendor frames 2 [internal]:0 Whoops\Run::handleShutdown() ``` ## 解决方案 通过研究框架代码,发现是没有正常关闭 Guzzle stream,导致内存一直累积无法回收 然后又在在 [vendor/laravel/framework/src/Illuminate/Http/Client/Response.php:247](https://github.com/laravel/framework/blob/10.x/src/Illuminate/Http/Client/Response.php#L247 "vendor/laravel/framework/src/Illuminate/Http/Client/Response.php:247") 位置发现有一个 `close()` 方法,但这个方法没有在任何地方使用,应该是想让你手动调用进行关闭 stream 所以将代码改成如下就可以了 ```php $url = 'https://xxxx/xxx.json'; $response = Illuminate\Support\Facades\Http::get($url); $json = $response->json(); // 关闭 stream $response->close(); // TODO 业务逻辑处理 ``` ## 附测试内存泄漏代码 ```php json(); printf("Count: %d\tPHP Memory: %.1fMB\n", $i++, memory_get_usage(true) / 1024.00 / 1024.00); } ``` ![](https://cdn.nowtime.cc/2023/12/06/138987942.png) ## 附测试修复内存泄漏后的代码 ```php body()) / 1024); $response->close(); } ``` ![](https://cdn.nowtime.cc/2023/12/06/3782614807.png)
Laravels + DcatAdmin 使用问题 作者: Chuwen 时间: 2023-12-04 分类: PHP 评论 如果按照 Laravels 的文档所说的,在 `config/laravels.php` 文件的 `cleaners` 数组加上: ```php 'cleaners' => [ Hhxsv5\LaravelS\Illuminate\Cleaners\SessionCleaner::class, Hhxsv5\LaravelS\Illuminate\Cleaners\AuthCleaner::class, Hhxsv5\LaravelS\Illuminate\Cleaners\DcatAdminCleaner::class ], ``` 实际上还是会有问题的,比如我遇到的就是菜单栏不会渲染问题 如果要解决这个问题也很简单,参照 https://github.com/hhxsv5/laravel-s/issues/251#issuecomment-971224092 写一个清理累去清理。 以下是我根据这个 issues 摘录的操作步骤 ## 步骤 1. 创建如 `app/Cleaners` 文件夹 2. 新建一个文件 `app/Cleaners/DcatAdminCleaner.php` 内容为 ```php currentApp); $flushAdminState->handle(null); } } ``` 3. 将 `config/laravels.php` 的内容 `Hhxsv5\LaravelS\Illuminate\Cleaners\DcatAdminCleaner::class` 替换为 `App\Cleaners\DcatAdminCleaner::class` 即可 ![](https://cdn.nowtime.cc/2023/12/04/1914189827.png)
记录一次 Node.js 构建失败的坑 (/bin/sh: vite:未找到命令 error Command failed with exit code 127.) 作者: Chuwen 时间: 2023-10-13 分类: WEB开发 评论 ## 问题排查 经过排查是 `vite` 包没安装上,然后我就想到了 `vite` 包是写在 `package.json` 文件的 `devDependencies` 清单中 最终查看 [yarn 文档](https://classic.yarnpkg.com/lang/en/docs/cli/install/#toc-yarn-install-production-true-false)发现一个配置项: 如果环境变量 `NODE_ENV` 设置为 `production`,则会忽略 `devDependencies` 清单中的包 然后看了一眼流水线环境变量配置,果不其然设置了 `NODE_ENV=production` 这个环境变量,这也印证了为什么构建时提示 `vite` 命令找不到 ## 解决方案 以下任选一个方案即可 ### 1. 将 NODE_ENV 环境变量删除 ### 2. 安装依赖时追加 `--production=false` 参数 完整示例:`yarn install --production=false`
Tailscale 搭建 derper, 使用 Nginx 反向代理遇到的坑: http: TLS handshake error from 172.40.0.1:44442: cert mismatch with hostname: "" 作者: Chuwen 时间: 2023-10-10 分类: 谈天说地 评论 ## 序言 按照网上找到的教程,大部分都是让你这么配置 Nginx: ```nginx location / { proxy_pass https://127.0.0.1:3443; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } ``` 但是这样做你会发现根本访问不了,derper 也会报出如下错误: ![](https://cdn.nowtime.cc/2023/10/10/1996389015.png) cert mismatch with hostname(证书与主机名不匹配) **异常原因(这是我的个人猜测,欢迎 dalao 们指正):** 可能是在 Nginx 在与后端 TLS 握手期间,deper 进行了对 SSL 强校验,发现 hostname 和证书的主机名不匹配,则拒绝连接 ## 解决方案 ```nginx location / { proxy_pass https://127.0.0.1:3443; proxy_http_version 1.1; proxy_set_header Host $host; # 加上这 2 行配置即可解决 proxy_ssl_server_name on; proxy_ssl_name $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } ``` 如果访问你的 derper 地址,出现以下界面表示配置成功 ![](https://cdn.nowtime.cc/2023/10/10/4151549465.png)
Tailscale 打洞失败解决方案 作者: Chuwen 时间: 2023-10-09 分类: 唠嗑闲聊 评论 添加一行这个配置 `"randomizeClientPort": true` 就可以了 ![](https://cdn.nowtime.cc/2023/10/09/1366708902.png)