From ad491c0f20422ec2cb111f8e6e6c9052829e2289 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Thu, 18 Dec 2025 19:07:00 +0800 Subject: [PATCH 1/7] fix(sentry): remove duplicate code and improve singleton instance reset in SingletonAspect - Remove duplicate variable assignments in SingletonAspect::process() - Add proper singleton instance reset logic using Closure::bind - Support both 'instance' and 'instances' property patterns - Ensure clean singleton behavior when context already exists --- src/sentry/src/Aspect/SingletonAspect.php | 28 +++++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/sentry/src/Aspect/SingletonAspect.php b/src/sentry/src/Aspect/SingletonAspect.php index 5c0aec6e4..e560b2358 100644 --- a/src/sentry/src/Aspect/SingletonAspect.php +++ b/src/sentry/src/Aspect/SingletonAspect.php @@ -11,6 +11,7 @@ namespace FriendsOfHyperf\Sentry\Aspect; +use Closure; use Hyperf\Context\Context; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; @@ -33,13 +34,30 @@ class SingletonAspect extends AbstractAspect public function process(ProceedingJoinPoint $proceedingJoinPoint) { - $key = $proceedingJoinPoint->className; - $args = $proceedingJoinPoint->getArguments(); + $key = $className = $proceedingJoinPoint->className; + $arguments = $proceedingJoinPoint->getArguments(); - if (! empty($args)) { - $key .= '#' . $args[0]; + if (! empty($arguments)) { + $key .= '#' . $arguments[0]; } - return Context::getOrSet($key, fn () => $proceedingJoinPoint->process()); + $key = $className = $proceedingJoinPoint->className; + $arguments = $proceedingJoinPoint->getArguments(); + + if (! empty($arguments)) { + $key .= '#' . $arguments[0]; + } + + return Context::getOrSet($key, function () use ($proceedingJoinPoint, $className, $arguments) { + // Reset singleton instance before proceeding + Closure::bind(function () use ($className, $arguments) { + match (true) { + property_exists($className, 'instance') => $className::$instance = null, + property_exists($className, 'instances') => $className::$instances[$arguments[0]] = null, + default => null, + }; + }, null, $className)(); + return $proceedingJoinPoint->process(); + }); } } From e901c56a71fcacc92d817afb552f7853bbbf8697 Mon Sep 17 00:00:00 2001 From: Deeka Wong Date: Thu, 18 Dec 2025 20:28:11 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20SingletonAspect.php?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/sentry/src/Aspect/SingletonAspect.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/sentry/src/Aspect/SingletonAspect.php b/src/sentry/src/Aspect/SingletonAspect.php index e560b2358..7ce33232f 100644 --- a/src/sentry/src/Aspect/SingletonAspect.php +++ b/src/sentry/src/Aspect/SingletonAspect.php @@ -41,13 +41,6 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $key .= '#' . $arguments[0]; } - $key = $className = $proceedingJoinPoint->className; - $arguments = $proceedingJoinPoint->getArguments(); - - if (! empty($arguments)) { - $key .= '#' . $arguments[0]; - } - return Context::getOrSet($key, function () use ($proceedingJoinPoint, $className, $arguments) { // Reset singleton instance before proceeding Closure::bind(function () use ($className, $arguments) { From d25dbcc2e11ab012696b0775e799c55cb5373d16 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Thu, 18 Dec 2025 21:39:25 +0800 Subject: [PATCH 3/7] fix(sentry): refine singleton instance reset logic in SingletonAspect --- src/sentry/src/Aspect/SingletonAspect.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/sentry/src/Aspect/SingletonAspect.php b/src/sentry/src/Aspect/SingletonAspect.php index 7ce33232f..e022d229f 100644 --- a/src/sentry/src/Aspect/SingletonAspect.php +++ b/src/sentry/src/Aspect/SingletonAspect.php @@ -37,19 +37,25 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint) $key = $className = $proceedingJoinPoint->className; $arguments = $proceedingJoinPoint->getArguments(); - if (! empty($arguments)) { + if (isset($arguments[0])) { $key .= '#' . $arguments[0]; } return Context::getOrSet($key, function () use ($proceedingJoinPoint, $className, $arguments) { // Reset singleton instance before proceeding Closure::bind(function () use ($className, $arguments) { - match (true) { - property_exists($className, 'instance') => $className::$instance = null, - property_exists($className, 'instances') => $className::$instances[$arguments[0]] = null, - default => null, - }; + if (property_exists($className, 'instance')) { + $className::$instance = null; + } elseif ( + property_exists($className, 'instances') + && isset($arguments[0]) + && array_key_exists($arguments[0], $className::$instances) + ) { + $className::$instances[$arguments[0]] = null; + } }, null, $className)(); + + // Proceed to get the singleton instance return $proceedingJoinPoint->process(); }); } From 005fe25536c09a003cdfc33282bbc78d85a7f4bb Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 19 Dec 2025 08:13:00 +0800 Subject: [PATCH 4/7] fix(metrics): remove unused spawnDefaultMetrics function in MetricSetter trait --- src/sentry/src/Metrics/Traits/MetricSetter.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sentry/src/Metrics/Traits/MetricSetter.php b/src/sentry/src/Metrics/Traits/MetricSetter.php index 89708ae0b..9b5a5f9db 100644 --- a/src/sentry/src/Metrics/Traits/MetricSetter.php +++ b/src/sentry/src/Metrics/Traits/MetricSetter.php @@ -31,8 +31,4 @@ protected function trySet(string $prefix, array $metrics, array $stats, int $wor } } } - - // protected function spawnDefaultMetrics() - // { - // } } From e62c962c0d8b9a907933898d9be070780bfae793 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 19 Dec 2025 08:42:54 +0800 Subject: [PATCH 5/7] =?UTF-8?q?fix(metrics):=20=E7=A7=BB=E9=99=A4=E5=86=97?= =?UTF-8?q?=E4=BD=99=E7=9A=84defer=E8=B0=83=E7=94=A8=EF=BC=8C=E7=9B=B4?= =?UTF-8?q?=E6=8E=A5=E5=9C=A8=E4=BA=8B=E4=BB=B6=E5=A4=84=E7=90=86=E5=90=8E?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E6=8C=87=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sentry/src/Metrics/Listener/OnBeforeHandle.php | 5 ++--- src/sentry/src/Metrics/Listener/OnCoroutineServerStart.php | 5 ++--- src/sentry/src/Metrics/Listener/OnMetricFactoryReady.php | 6 +++--- src/sentry/src/Metrics/Listener/OnWorkerStart.php | 5 ++--- src/sentry/src/Metrics/Listener/PoolWatcher.php | 5 ++--- src/sentry/src/Metrics/Listener/QueueWatcher.php | 5 ++--- 6 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/sentry/src/Metrics/Listener/OnBeforeHandle.php b/src/sentry/src/Metrics/Listener/OnBeforeHandle.php index de9691bb1..15472535a 100644 --- a/src/sentry/src/Metrics/Listener/OnBeforeHandle.php +++ b/src/sentry/src/Metrics/Listener/OnBeforeHandle.php @@ -21,7 +21,6 @@ use Sentry\Unit; use function FriendsOfHyperf\Sentry\metrics; -use function Hyperf\Coroutine\defer; class OnBeforeHandle implements ListenerInterface { @@ -93,8 +92,6 @@ public function process(object $event): void return Timer::STOP; } - defer(fn () => metrics()->flush()); - $this->trySet('gc_', $metrics, gc_status()); $this->trySet('', $metrics, getrusage()); @@ -110,6 +107,8 @@ public function process(object $event): void ['worker' => '0'], Unit::megabyte() ); + + metrics()->flush(); }); } } diff --git a/src/sentry/src/Metrics/Listener/OnCoroutineServerStart.php b/src/sentry/src/Metrics/Listener/OnCoroutineServerStart.php index cf371a4aa..3fff861b6 100644 --- a/src/sentry/src/Metrics/Listener/OnCoroutineServerStart.php +++ b/src/sentry/src/Metrics/Listener/OnCoroutineServerStart.php @@ -22,7 +22,6 @@ use Sentry\Unit; use function FriendsOfHyperf\Sentry\metrics; -use function Hyperf\Coroutine\defer; class OnCoroutineServerStart implements ListenerInterface { @@ -102,8 +101,6 @@ public function process(object $event): void return Timer::STOP; } - defer(fn () => metrics()->flush()); - $this->trySet('gc_', $metrics, gc_status()); $this->trySet('', $metrics, getrusage()); @@ -119,6 +116,8 @@ public function process(object $event): void ['worker' => '0'], Unit::megabyte() ); + + metrics()->flush(); }); } } diff --git a/src/sentry/src/Metrics/Listener/OnMetricFactoryReady.php b/src/sentry/src/Metrics/Listener/OnMetricFactoryReady.php index ada52adbb..3496791cc 100644 --- a/src/sentry/src/Metrics/Listener/OnMetricFactoryReady.php +++ b/src/sentry/src/Metrics/Listener/OnMetricFactoryReady.php @@ -25,7 +25,6 @@ use Swoole\Server as SwooleServer; use function FriendsOfHyperf\Sentry\metrics; -use function Hyperf\Coroutine\defer; class OnMetricFactoryReady implements ListenerInterface { @@ -101,8 +100,6 @@ public function process(object $event): void return Timer::STOP; } - defer(fn () => metrics()->flush()); - $this->trySet('', $metrics, Coroutine::stats(), $workerId); $this->trySet('timer_', $metrics, Timer::stats(), $workerId); @@ -115,6 +112,7 @@ public function process(object $event): void } $load = sys_getloadavg(); + metrics()->gauge( 'sys_load', round($load[0] / System::getCpuCoresNum(), 2), @@ -132,6 +130,8 @@ public function process(object $event): void ['worker' => (string) $workerId], Unit::megabyte() ); + + metrics()->flush(); }); } } diff --git a/src/sentry/src/Metrics/Listener/OnWorkerStart.php b/src/sentry/src/Metrics/Listener/OnWorkerStart.php index 046d33798..a038813fc 100644 --- a/src/sentry/src/Metrics/Listener/OnWorkerStart.php +++ b/src/sentry/src/Metrics/Listener/OnWorkerStart.php @@ -23,7 +23,6 @@ use Swoole\Server; use function FriendsOfHyperf\Sentry\metrics; -use function Hyperf\Coroutine\defer; class OnWorkerStart implements ListenerInterface { @@ -92,8 +91,6 @@ public function process(object $event): void return Timer::STOP; } - defer(fn () => metrics()->flush()); - $server = $this->container->get(Server::class); $serverStats = $server->stats(); $this->trySet('gc_', $metrics, gc_status()); @@ -121,6 +118,8 @@ public function process(object $event): void ['worker' => (string) ($event->workerId ?? 0)], Unit::megabyte() ); + + metrics()->flush(); }); } } diff --git a/src/sentry/src/Metrics/Listener/PoolWatcher.php b/src/sentry/src/Metrics/Listener/PoolWatcher.php index d39d3d6c9..caab50d47 100644 --- a/src/sentry/src/Metrics/Listener/PoolWatcher.php +++ b/src/sentry/src/Metrics/Listener/PoolWatcher.php @@ -20,7 +20,6 @@ use Psr\Container\ContainerInterface; use function FriendsOfHyperf\Sentry\metrics; -use function Hyperf\Coroutine\defer; abstract class PoolWatcher implements ListenerInterface { @@ -71,8 +70,6 @@ public function watch(Pool $pool, string $poolName, int $workerId): void return Timer::STOP; } - defer(fn () => metrics()->flush()); - metrics()->gauge( $this->getPrefix() . '_connections_in_use', (float) $pool->getCurrentConnections(), @@ -97,6 +94,8 @@ public function watch(Pool $pool, string $poolName, int $workerId): void 'worker' => (string) $workerId, ] ); + + metrics()->flush(); }); } } diff --git a/src/sentry/src/Metrics/Listener/QueueWatcher.php b/src/sentry/src/Metrics/Listener/QueueWatcher.php index d666d6b6a..c25c97699 100644 --- a/src/sentry/src/Metrics/Listener/QueueWatcher.php +++ b/src/sentry/src/Metrics/Listener/QueueWatcher.php @@ -20,7 +20,6 @@ use Psr\Container\ContainerInterface; use function FriendsOfHyperf\Sentry\metrics; -use function Hyperf\Coroutine\defer; class QueueWatcher implements ListenerInterface { @@ -57,8 +56,6 @@ public function process(object $event): void return Timer::STOP; } - defer(fn () => metrics()->flush()); - $config = $this->container->get(ConfigInterface::class); $queues = array_keys($config->get('async_queue', [])); @@ -87,6 +84,8 @@ public function process(object $event): void ['queue' => $name] ); } + + metrics()->flush(); }); } } From 9fc88695dab897d014fcf117f4eda87592b12e21 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 19 Dec 2025 08:50:14 +0800 Subject: [PATCH 6/7] =?UTF-8?q?fix(metrics):=20=E7=A7=BB=E9=99=A4defer?= =?UTF-8?q?=E8=B0=83=E7=94=A8=EF=BC=8C=E7=9B=B4=E6=8E=A5=E5=9C=A8=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E5=A4=84=E7=90=86=E5=90=8E=E5=88=B7=E6=96=B0=E6=8C=87?= =?UTF-8?q?=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sentry/src/Metrics/Aspect/CounterAspect.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sentry/src/Metrics/Aspect/CounterAspect.php b/src/sentry/src/Metrics/Aspect/CounterAspect.php index b6f25911a..6991903f9 100644 --- a/src/sentry/src/Metrics/Aspect/CounterAspect.php +++ b/src/sentry/src/Metrics/Aspect/CounterAspect.php @@ -17,7 +17,6 @@ use Hyperf\Di\Aop\ProceedingJoinPoint; use function FriendsOfHyperf\Sentry\metrics; -use function Hyperf\Coroutine\defer; class CounterAspect extends AbstractAspect { @@ -46,12 +45,12 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint): mixed $name = $source; } - defer(fn () => metrics()->flush()); - metrics()->count($name, 1, [ 'class' => $proceedingJoinPoint->className, 'method' => $proceedingJoinPoint->methodName, ]); + + metrics()->flush(); } return $proceedingJoinPoint->process(); From a8f7c682a43cc1f233db3e0fd7b75b77579bc791 Mon Sep 17 00:00:00 2001 From: Deeka Wong <8337659+huangdijia@users.noreply.github.com> Date: Fri, 19 Dec 2025 08:56:41 +0800 Subject: [PATCH 7/7] =?UTF-8?q?fix(coroutine):=20=E6=9B=BF=E6=8D=A2defer?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E4=B8=BACoroutine::defer=E4=BB=A5=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E5=8D=8F=E7=A8=8B=E5=A4=84=E7=90=86=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sentry/src/Metrics/Aspect/HistogramAspect.php | 4 ++-- src/sentry/src/Metrics/Listener/RequestWatcher.php | 4 ++-- src/sentry/src/Tracing/Aspect/CoroutineAspect.php | 3 +-- .../src/Tracing/Listener/EventHandleListener.php | 12 ++++++------ src/sentry/src/Tracing/Tracer.php | 9 ++++----- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/sentry/src/Metrics/Aspect/HistogramAspect.php b/src/sentry/src/Metrics/Aspect/HistogramAspect.php index 50845cf19..452db7dbf 100644 --- a/src/sentry/src/Metrics/Aspect/HistogramAspect.php +++ b/src/sentry/src/Metrics/Aspect/HistogramAspect.php @@ -16,8 +16,8 @@ use FriendsOfHyperf\Sentry\Metrics\Timer; use Hyperf\Di\Aop\AbstractAspect; use Hyperf\Di\Aop\ProceedingJoinPoint; +use Hyperf\Engine\Coroutine as Co; -use function Hyperf\Coroutine\defer; use function Hyperf\Tappable\tap; class HistogramAspect extends AbstractAspect @@ -54,7 +54,7 @@ public function process(ProceedingJoinPoint $proceedingJoinPoint): mixed ]); return tap($proceedingJoinPoint->process(), function () use ($timer) { - defer(fn () => $timer->end(true)); + Co::defer(fn () => $timer->end(true)); }); } diff --git a/src/sentry/src/Metrics/Listener/RequestWatcher.php b/src/sentry/src/Metrics/Listener/RequestWatcher.php index 10bfd66b8..7e08eb972 100644 --- a/src/sentry/src/Metrics/Listener/RequestWatcher.php +++ b/src/sentry/src/Metrics/Listener/RequestWatcher.php @@ -13,7 +13,7 @@ use FriendsOfHyperf\Sentry\Metrics\CoroutineServerStats; use FriendsOfHyperf\Sentry\Metrics\Timer; -use Hyperf\Engine\Coroutine; +use Hyperf\Engine\Coroutine as Co; use Hyperf\Event\Contract\ListenerInterface; use Hyperf\HttpServer\Event as HttpEvent; use Hyperf\HttpServer\Router\Dispatched; @@ -49,7 +49,7 @@ public function process(object $event): void 'request_method' => $request->getMethod(), ]); - Coroutine::defer(function () use ($timer) { + Co::defer(function () use ($timer) { ++$this->stats->close_count; ++$this->stats->response_count; --$this->stats->connection_num; diff --git a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php index bc0170170..f3c58fa82 100644 --- a/src/sentry/src/Tracing/Aspect/CoroutineAspect.php +++ b/src/sentry/src/Tracing/Aspect/CoroutineAspect.php @@ -25,7 +25,6 @@ use function FriendsOfHyperf\Sentry\startTransaction; use function FriendsOfHyperf\Sentry\trace; -use function Hyperf\Coroutine\defer; use function Sentry\continueTrace; class CoroutineAspect extends AbstractAspect @@ -83,7 +82,7 @@ function (Scope $scope) use ($proceedingJoinPoint, $callingOnFunction) { ); // Defer the finishing of the transaction and flushing of events until the coroutine completes. - defer(function () use ($transaction) { + Co::defer(function () use ($transaction) { $transaction->finish(); Integration::flushEvents(); }); diff --git a/src/sentry/src/Tracing/Listener/EventHandleListener.php b/src/sentry/src/Tracing/Listener/EventHandleListener.php index 8d0df8b08..b88191973 100644 --- a/src/sentry/src/Tracing/Listener/EventHandleListener.php +++ b/src/sentry/src/Tracing/Listener/EventHandleListener.php @@ -29,6 +29,7 @@ use Hyperf\Crontab\Event as CrontabEvent; use Hyperf\Database\Events as DbEvent; use Hyperf\DbConnection\Pool\PoolFactory; +use Hyperf\Engine\Coroutine as Co; use Hyperf\Event\Contract\ListenerInterface; use Hyperf\HttpServer\Event as HttpEvent; use Hyperf\HttpServer\Router\Dispatched; @@ -54,7 +55,6 @@ use function FriendsOfHyperf\Sentry\startTransaction; use function FriendsOfHyperf\Sentry\trace; -use function Hyperf\Coroutine\defer; use function Sentry\continueTrace; /** @@ -328,7 +328,7 @@ protected function handleRequestReceived(HttpEvent\RequestReceived|RpcEvent\Requ SentrySdk::getCurrentHub()->setSpan($span); - defer(function () use ($transaction, $span) { + Co::defer(function () use ($transaction, $span) { // Make sure the span is finished after the request is handled $span->finish(); @@ -531,7 +531,7 @@ protected function handleCrontabTaskStarting(CrontabEvent\BeforeExecute $event): ]) ); - defer(function () use ($transaction) { + Co::defer(function () use ($transaction) { // Make sure the transaction is finished after the task is executed SentrySdk::getCurrentHub()->setSpan($transaction); @@ -600,7 +600,7 @@ protected function handleAmqpMessageProcessing(AmqpEvent\BeforeConsume $event): ]) ); - defer(function () use ($transaction) { + Co::defer(function () use ($transaction) { // Make sure the transaction is finished after the message is processed SentrySdk::getCurrentHub()->setSpan($transaction); @@ -668,7 +668,7 @@ protected function handleKafkaMessageProcessing(KafkaEvent\BeforeConsume $event) ]) ); - defer(function () use ($transaction) { + Co::defer(function () use ($transaction) { // Make sure the transaction is finished after the message is processed SentrySdk::getCurrentHub()->setSpan($transaction); @@ -718,7 +718,7 @@ protected function handleAsyncQueueJobProcessing(AsyncQueueEvent\BeforeHandle $e ]) ); - defer(function () use ($transaction) { + Co::defer(function () use ($transaction) { // Make sure the transaction is finished after the job is processed SentrySdk::getCurrentHub()->setSpan($transaction); diff --git a/src/sentry/src/Tracing/Tracer.php b/src/sentry/src/Tracing/Tracer.php index 60c216909..0c9a3e885 100644 --- a/src/sentry/src/Tracing/Tracer.php +++ b/src/sentry/src/Tracing/Tracer.php @@ -11,7 +11,7 @@ namespace FriendsOfHyperf\Sentry\Tracing; -use Hyperf\Engine\Coroutine; +use Hyperf\Engine\Coroutine as Co; use Sentry\SentrySdk; use Sentry\State\Scope; use Sentry\Tracing\SpanContext; @@ -21,7 +21,6 @@ use Sentry\Tracing\TransactionSource; use Throwable; -use function Hyperf\Coroutine\defer; use function Sentry\trace; class Tracer @@ -35,9 +34,9 @@ public function startTransaction(TransactionContext $transactionContext, array $ $hub->pushScope(); $hub->configureScope(static fn (Scope $scope) => $scope->clearBreadcrumbs()); - defer(static fn () => $hub->popScope()); + Co::defer(static fn () => $hub->popScope()); - $transactionContext->setData(['coroutine.id' => Coroutine::id()] + $transactionContext->getData()); + $transactionContext->setData(['coroutine.id' => Co::id()] + $transactionContext->getData()); if ($transactionContext->getStartTimestamp() === null) { $transactionContext->setStartTimestamp(microtime(true)); @@ -77,7 +76,7 @@ public function trace(callable $trace, SpanContext $context) $context->setStartTimestamp(microtime(true)); } - $context->setData(['coroutine.id' => Coroutine::id()] + $context->getData()); + $context->setData(['coroutine.id' => Co::id()] + $context->getData()); return trace( function (Scope $scope) use ($trace) {