feat: 优化请求上下文处理

This commit is contained in:
kuaifan 2025-07-30 18:32:23 +08:00
parent f6cab9b5a9
commit a1a51914a2
4 changed files with 227 additions and 66 deletions

View File

@ -76,6 +76,6 @@ class WebApi
public function terminate()
{
// 请求结束后清理上下文
RequestContext::clear();
RequestContext::clean();
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace App\Module;
/**
* 客户端上下文
*/
class ClientContext
{
public array $context = [];
public float $createdAt = 0;
public float $updatedAt = 0;
public function __construct()
{
$this->createdAt = microtime(true);
$this->updatedAt = microtime(true);
}
/**
* 设置上下文
* @param string $key
* @param mixed $value
* @return void
*/
public function set(string $key, mixed $value): void
{
$this->context[$key] = $value;
$this->updatedAt = microtime(true);
}
/**
* 批量设置上下文
* @param array $data
* @return void
*/
public function setMultiple(array $data): void
{
foreach ($data as $key => $value) {
$this->context[$key] = $value;
}
$this->updatedAt = microtime(true);
}
/**
* 获取上下文
* @param string $key
* @param mixed $default
* @return mixed
*/
public function get(string $key, mixed $default = null): mixed
{
return $this->context[$key] ?? $default;
}
/**
* 判断上下文是否存在
* @param string $key
* @return bool
*/
public function has(string $key): bool
{
return isset($this->context[$key]);
}
/**
* 更新上下文
* @return void
*/
public function update(): void
{
$this->updatedAt = microtime(true);
}
/**
* 清除上下文
* @return void
*/
public function clear(): void
{
$this->context = [];
}
}

View File

@ -4,14 +4,17 @@ namespace App\Module;
use App\Exceptions\ApiException;
use App\Models\User;
use App\Services\RequestContext;
use Cache;
use Carbon\Carbon;
use FFI;
use FFI\CData;
use FFI\Exception;
class Doo
{
private static $doo;
private static $userLanguage = "";
private const DOO_INSTANCE = 'doo_instance';
private const DOO_LANGUAGE = 'doo_language';
/**
* char转为字符串
@ -20,17 +23,26 @@ class Doo
*/
private static function string($text): string
{
return FFI::string($text);
if (!($text instanceof CData)) {
return "";
}
try {
return FFI::string($text);
} catch (Exception) {
return "";
}
}
/**
* 装载
* @param $token
* @param $language
* @return FFI
*/
public static function load($token = null, $language = null)
{
self::$doo = FFI::cdef(<<<EOF
$instance = FFI::cdef(<<<EOF
void initialize(char* work, char* token, char* lang);
char* license();
char* licenseDecode(char* license);
@ -54,7 +66,12 @@ class Doo
EOF, "/usr/lib/doo/doo.so");
$token = $token ?: Base::token();
$language = $language ?: Base::headerOrInput('language');
self::$doo->initialize("/var/www", $token, $language);
$instance->initialize("/var/www", $token, $language);
RequestContext::set(self::DOO_INSTANCE, $instance);
RequestContext::set(self::DOO_LANGUAGE, $language);
return $instance;
}
/**
@ -65,10 +82,11 @@ class Doo
*/
public static function doo($token = null, $language = null)
{
if (self::$doo == null) {
self::load($token, $language);
$instance = RequestContext::get(self::DOO_INSTANCE);
if ($instance === null) {
$instance = self::load($token, $language);
}
return self::$doo;
return $instance;
}
/**
@ -277,19 +295,25 @@ class Doo
*/
public static function translate($text, string $lang = ""): string
{
return self::string(self::doo()->translate($text, $lang ?: self::$userLanguage));
if (empty($text)) {
return "";
}
if (empty($lang)) {
$lang = RequestContext::get(self::DOO_LANGUAGE);
}
return self::string(self::doo()->translate($text, $lang));
}
/**
* 设置语言
* @param string|integer $lang 语言 会员ID
* @param string|int $lang 语言 会员ID
* @return void
*/
public static function setLanguage($lang) {
if (Base::isNumber($lang)) {
$lang = User::find(intval($lang))?->lang ?: "";
}
self::$userLanguage = $lang;
RequestContext::set(self::DOO_LANGUAGE, $lang);
}
/**

View File

@ -2,33 +2,84 @@
namespace App\Services;
use App\Module\ClientContext;
use Illuminate\Http\Request;
use Swoole\Coroutine;
/**
* 请求上下文
*/
class RequestContext
{
/** @var array<string, array<string, mixed>> */
private static array $context = [];
private const REQUEST_ID_PREFIX = 'req_';
/** @var string 请求ID前缀 */
private const REQUEST_ID_PREFIX = 'req';
/** @var int 上下文的TTL生存时间 */
private const TTL_SECONDS = 3600; // 上下文 TTL 为 1 小时
/** @var array<string, ClientContext> 存储每个请求的上下文数据 */
private static array $context = [];
/**
* 生成请求唯一ID
*/
public static function generateRequestId(): string
{
return self::REQUEST_ID_PREFIX . uniqid() . mt_rand(10000, 99999);
$pid = getmypid();
$cid = Coroutine::getCid() ?? 0;
$microtime = str_replace('.', '', microtime(true));
return self::REQUEST_ID_PREFIX . '_' . $pid . '_' . $cid . '_' . $microtime . '_' . mt_rand(1000, 9999);
}
/**
* 获取当前请求ID
*/
private static function getCurrentRequestId(): ?string
public static function getCurrentRequestId($requestId = null): ?string
{
/** @var Request $request */
$request = request();
return $request?->requestId;
return $requestId ?? request()?->requestId;
}
/**
* 获取当前请求的上下文示例
*/
public static function getCurrentRequestContext($requestId = null): ?ClientContext
{
$requestId = self::getCurrentRequestId($requestId);
if ($requestId === null) {
return null;
}
if (!isset(self::$context[$requestId])) {
// 如果上下文不存在,则创建一个新的上下文
self::$context[$requestId] = new ClientContext();
} else {
// 如果上下文已存在,更新访问时间
self::$context[$requestId]->update();
}
return self::$context[$requestId];
}
/**
* 清理过期上下文数据,防止内存泄漏
*/
public static function cleanExpired(): void
{
$now = microtime(true);
// 清理过期的上下文
foreach (self::$context as $requestId => $context) {
if ($now - $context->updatedAt > self::TTL_SECONDS) {
unset(self::$context[$requestId]);
}
}
}
/** ***************************************************************************************** */
/** ***************************************************************************************** */
/** ***************************************************************************************** */
/**
* 设置请求上下文
*
@ -39,13 +90,34 @@ class RequestContext
*/
public static function set(string $key, mixed $value, ?string $requestId = null): void
{
$requestId = $requestId ?? self::getCurrentRequestId();
if ($requestId === null) {
$context = self::getCurrentRequestContext($requestId);
if ($context === null) {
return;
}
self::$context[$requestId] ??= [];
self::$context[$requestId][$key] = $value;
$context->set($key, $value);
// 概率性清理,避免频繁清理影响性能
if (mt_rand(1, 100) === 1) {
self::cleanExpired();
}
}
/**
* 批量设置上下文数据
*
* @param array<string, mixed> $data
* @param string|null $requestId
* @return void
*/
public static function setMultiple(array $data, ?string $requestId = null): void
{
$context = self::getCurrentRequestContext($requestId);
if ($context === null) {
return;
}
$context->setMultiple($data);
}
// 与 set 方法的区别是save 方法会返回传入的 value 值
@ -65,12 +137,28 @@ class RequestContext
*/
public static function get(string $key, mixed $default = null, ?string $requestId = null): mixed
{
$requestId = $requestId ?? self::getCurrentRequestId();
if ($requestId === null) {
$context = self::getCurrentRequestContext($requestId);
if ($context === null) {
return $default;
}
return self::$context[$requestId][$key] ?? $default;
return $context->get($key, $default);
}
/**
* 获取当前请求的所有上下文数据
*
* @param string|null $requestId
* @return array<string, mixed>
*/
public static function getAll(?string $requestId = null): array
{
$context = self::getCurrentRequestContext($requestId);
if ($context === null) {
return [];
}
return $context->context ?? [];
}
/**
@ -82,12 +170,12 @@ class RequestContext
*/
public static function has(string $key, ?string $requestId = null): bool
{
$requestId = $requestId ?? self::getCurrentRequestId();
if ($requestId === null) {
$context = self::getCurrentRequestContext($requestId);
if ($context === null) {
return false;
}
return isset(self::$context[$requestId][$key]);
return $context->has($key);
}
/**
@ -96,9 +184,9 @@ class RequestContext
* @param string|null $requestId
* @return void
*/
public static function clear(?string $requestId = null): void
public static function clean(?string $requestId = null): void
{
$requestId = $requestId ?? self::getCurrentRequestId();
$requestId = self::getCurrentRequestId($requestId);
if ($requestId === null) {
return;
}
@ -106,40 +194,6 @@ class RequestContext
unset(self::$context[$requestId]);
}
/**
* 获取当前请求的所有上下文数据
*
* @param string|null $requestId
* @return array<string, mixed>
*/
public static function getAll(?string $requestId = null): array
{
$requestId = $requestId ?? self::getCurrentRequestId();
if ($requestId === null) {
return [];
}
return self::$context[$requestId] ?? [];
}
/**
* 批量设置上下文数据
*
* @param array<string, mixed> $data
* @param string|null $requestId
* @return void
*/
public static function setMultiple(array $data, ?string $requestId = null): void
{
$requestId = $requestId ?? self::getCurrentRequestId();
if ($requestId === null) {
return;
}
self::$context[$requestId] ??= [];
self::$context[$requestId] = array_merge(self::$context[$requestId], $data);
}
/** ***************************************************************************************** */
/** ***************************************************************************************** */
/** ***************************************************************************************** */