From 1c880f28052d88c920806f7c2423b3ad98c26c4d Mon Sep 17 00:00:00 2001 From: Deeka Wong Date: Wed, 3 Jan 2024 15:55:58 +0800 Subject: [PATCH] Send Event asynchronously (#513) * Adds AsyncHttpClient * Update ClientBuilderFactory and Version classes * Refactor AsyncHttpClient to use arrow function * Fix formatting in AsyncHttpClient * Update Sentry HttpClientInterface implementation * Remove useless codes * Add Hyperf\Engine\Channel import to HttpClient.php * Refactor HttpClient and HttpClientFactory * Add http_client_chanel_size and http_client_concurrent_limit configuration options * Add http options * Refactor HttpClient.php to use Hyperf\Engine\Coroutine instead of Hyperf\Coroutine\Coroutine --------- Co-authored-by: Deeka Wong <8337659+huangdijia@users.noreply.github.com> --- publish/sentry.php | 4 ++ src/ConfigProvider.php | 1 + src/Factory/ClientBuilderFactory.php | 20 ++++-- src/HttpClient/HttpClient.php | 101 +++++++++++++++++++++++++++ src/HttpClient/HttpClientFactory.php | 30 ++++++++ src/Version.php | 12 ++++ 6 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 src/HttpClient/HttpClient.php create mode 100644 src/HttpClient/HttpClientFactory.php diff --git a/publish/sentry.php b/publish/sentry.php index 7c8a651..16957dd 100644 --- a/publish/sentry.php +++ b/publish/sentry.php @@ -197,4 +197,8 @@ ], ], ], + + 'http_timeout' => (float) env('SENTRY_HTTP_TIMEOUT', 2.0), + 'http_chanel_size' => (int) env('SENTRY_HTTP_CHANEL_SIZE', 65535), + 'http_concurrent_limit' => (int) env('SENTRY_HTTP_CONCURRENT_LIMIT', 100), ]; diff --git a/src/ConfigProvider.php b/src/ConfigProvider.php index bdf7114..53d8657 100644 --- a/src/ConfigProvider.php +++ b/src/ConfigProvider.php @@ -41,6 +41,7 @@ public function __invoke(): array 'dependencies' => [ \Sentry\ClientBuilder::class => Factory\ClientBuilderFactory::class, \Sentry\State\HubInterface::class => Factory\HubFactory::class, + \Sentry\HttpClient\HttpClientInterface::class => HttpClient\HttpClientFactory::class, ], 'listeners' => [ Listener\AmqpExceptionListener::class, diff --git a/src/Factory/ClientBuilderFactory.php b/src/Factory/ClientBuilderFactory.php index 39e3e32..3878511 100644 --- a/src/Factory/ClientBuilderFactory.php +++ b/src/Factory/ClientBuilderFactory.php @@ -13,9 +13,9 @@ use FriendsOfHyperf\Sentry\Version; use Hyperf\Contract\ConfigInterface; -use Hyperf\Support\Composer; use Psr\Container\ContainerInterface; use Sentry\ClientBuilder; +use Sentry\HttpClient\HttpClientInterface; use function Hyperf\Support\env; use function Hyperf\Tappable\tap; @@ -28,6 +28,8 @@ class ClientBuilderFactory 'integrations', 'enable', 'tracing', + 'http_chanel_size', + 'http_concurrent_limit', ]; public function __invoke(ContainerInterface $container) @@ -63,10 +65,16 @@ public function __invoke(ContainerInterface $container) $options['environment'] = env('APP_ENV', 'production'); } - return tap(ClientBuilder::create($options), function (ClientBuilder $clientBuilder) { - $clientBuilder->setSdkIdentifier(Version::SDK_IDENTIFIER); - $sdkVersion = Composer::getVersions()['friendsofhyperf/sentry'] ?? Version::SDK_VERSION; - $clientBuilder->setSdkVersion($sdkVersion); - }); + if ( + ! ($options['http_client'] ?? null) instanceof HttpClientInterface + && $container->has(HttpClientInterface::class) + ) { + $options['http_client'] = $container->get(HttpClientInterface::class); + } + + return tap( + ClientBuilder::create($options), + fn (ClientBuilder $clientBuilder) => $clientBuilder->setSdkIdentifier(Version::getSdkIdentifier())->setSdkVersion(Version::getSdkVersion()) + ); } } diff --git a/src/HttpClient/HttpClient.php b/src/HttpClient/HttpClient.php new file mode 100644 index 0000000..6b214df --- /dev/null +++ b/src/HttpClient/HttpClient.php @@ -0,0 +1,101 @@ + 0) { + $this->concurrent = new Concurrent($concurrentLimit); + } + } + + public function sendRequest(Request $request, Options $options): Response + { + $this->loop(); + + $chan = $this->chan; + $chan->push(fn () => parent::sendRequest($request, $options)); + + return new Response(202, [], 'Waiting for sendRequest'); + } + + public function close(): void + { + $chan = $this->chan; + $this->chan = null; + + $chan?->close(); + } + + protected function loop(): void + { + if ($this->chan != null) { + return; + } + + $this->chan = new Channel($this->channelSize); + + Coroutine::create(function () { + while (true) { + while (true) { + /** @var Closure|null $closure */ + $closure = $this->chan?->pop(); + if (! $closure) { + break 2; + } + try { + if ($this->concurrent) { + $this->concurrent->create($closure); + } else { + Coroutine::create($closure); + } + } catch (Throwable) { + break; + } finally { + $closure = null; + } + } + } + + $this->close(); + }); + + Coroutine::create(function () { + if (CoordinatorManager::until(Constants::WORKER_EXIT)->yield()) { + $this->close(); + } + }); + } +} diff --git a/src/HttpClient/HttpClientFactory.php b/src/HttpClient/HttpClientFactory.php new file mode 100644 index 0000000..8e56f3e --- /dev/null +++ b/src/HttpClient/HttpClientFactory.php @@ -0,0 +1,30 @@ +get(ConfigInterface::class); + return new HttpClient( + Version::getSdkIdentifier(), + Version::getSdkVersion(), + (int) $config->get('sentry.http_chanel_size', 65535), + (int) $config->get('sentry.http_concurrent_limit', 100) + ); + } +} diff --git a/src/Version.php b/src/Version.php index e2c5ca6..4c2a7e0 100644 --- a/src/Version.php +++ b/src/Version.php @@ -11,9 +11,21 @@ namespace FriendsOfHyperf\Sentry; +use Hyperf\Support\Composer; + final class Version { public const SDK_IDENTIFIER = 'sentry.php.hyperf'; public const SDK_VERSION = '3.1.0'; + + public static function getSdkIdentifier(): string + { + return self::SDK_IDENTIFIER; + } + + public static function getSdkVersion(): string + { + return Composer::getVersions()['friendsofhyperf/sentry'] ?? self::SDK_VERSION; + } }