From d734b8da96c5235015904ddd06646a5b38956593 Mon Sep 17 00:00:00 2001 From: "Buster \"Silver Eagle\" Neece" Date: Sun, 18 Apr 2021 00:03:22 -0500 Subject: [PATCH] Add profiler helper notifications and optimize cache usage. --- Dockerfile | 4 +- config/events.php | 4 ++ config/services.php | 18 +++-- .../Command/MessageQueue/ProcessCommand.php | 2 + src/Environment.php | 19 ++++++ .../ResetArrayCacheMiddleware.php | 37 ++++++++++ .../Check/ProfilerAdvisorCheck.php | 68 +++++++++++++++++++ 7 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 src/MessageQueue/ResetArrayCacheMiddleware.php create mode 100644 src/Notification/Check/ProfilerAdvisorCheck.php diff --git a/Dockerfile b/Dockerfile index d545f1d84..68d28572e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -58,7 +58,9 @@ ENV LANG="en_US.UTF-8" \ COMPOSER_PLUGIN_MODE="false" \ ADDITIONAL_MEDIA_SYNC_WORKER_COUNT=0 \ PROFILING_EXTENSION_ENABLED=0 \ - PROFILING_EXTENSION_ALWAYS_ON=0 + PROFILING_EXTENSION_ALWAYS_ON=0 \ + PROFILING_EXTENSION_HTTP_KEY=dev \ + PROFILING_EXTENSION_HTTP_IP_WHITELIST=127.0.0.1 # Entrypoint and default command ENTRYPOINT ["/usr/local/bin/uptime_wait"] diff --git a/config/events.php b/config/events.php index 678bef5ff..de07845cb 100644 --- a/config/events.php +++ b/config/events.php @@ -150,6 +150,10 @@ return function (App\EventDispatcher $dispatcher) { Event\GetNotifications::class, App\Notification\Check\SyncTaskCheck::class ); + $dispatcher->addCallableListener( + Event\GetNotifications::class, + App\Notification\Check\ProfilerAdvisorCheck::class + ); $dispatcher->addCallableListener( Event\Media\GetAlbumArt::class, diff --git a/config/services.php b/config/services.php index 65030a971..589212345 100644 --- a/config/services.php +++ b/config/services.php @@ -150,14 +150,22 @@ return [ Psr\Log\LoggerInterface $logger, ContainerInterface $di ) { + $arrayAdapter = new Symfony\Component\Cache\Adapter\ArrayAdapter(); + $arrayAdapter->setLogger($logger); + if ($environment->isTesting()) { - $adapter = new Symfony\Component\Cache\Adapter\ArrayAdapter(); - } else { - $adapter = new Symfony\Component\Cache\Adapter\RedisAdapter($di->get(Redis::class)); + return $arrayAdapter; } - $adapter->setLogger($logger); - return $adapter; + $redisAdapter = new Symfony\Component\Cache\Adapter\RedisAdapter($di->get(Redis::class)); + $redisAdapter->setLogger($logger); + + return new Symfony\Component\Cache\Adapter\ChainAdapter( + [ + $arrayAdapter, + $redisAdapter, + ] + ); }, Psr\Cache\CacheItemPoolInterface::class => DI\get( diff --git a/src/Console/Command/MessageQueue/ProcessCommand.php b/src/Console/Command/MessageQueue/ProcessCommand.php index 8fce57100..365c3c92d 100644 --- a/src/Console/Command/MessageQueue/ProcessCommand.php +++ b/src/Console/Command/MessageQueue/ProcessCommand.php @@ -9,6 +9,7 @@ use App\EventDispatcher; use App\MessageQueue\LogWorkerExceptionSubscriber; use App\MessageQueue\QueueManager; use App\MessageQueue\ReloadSettingsMiddleware; +use App\MessageQueue\ResetArrayCacheMiddleware; use Psr\Log\LoggerInterface; use Symfony\Component\Messenger\EventListener\StopWorkerOnTimeLimitListener; use Symfony\Component\Messenger\MessageBus; @@ -42,6 +43,7 @@ class ProcessCommand extends CommandAbstract $eventDispatcher->addServiceSubscriber(ClearEntityManagerSubscriber::class); $eventDispatcher->addServiceSubscriber(LogWorkerExceptionSubscriber::class); $eventDispatcher->addServiceSubscriber(ReloadSettingsMiddleware::class); + $eventDispatcher->addServiceSubscriber(ResetArrayCacheMiddleware::class); if ($runtime <= 0) { $runtime = $environment->isProduction() diff --git a/src/Environment.php b/src/Environment.php index d151e94ed..d2a2f6e49 100644 --- a/src/Environment.php +++ b/src/Environment.php @@ -48,6 +48,10 @@ class Environment public const LOG_LEVEL = 'LOG_LEVEL'; + public const PROFILING_EXTENSION_ENABLED = 'PROFILING_EXTENSION_ENABLED'; + public const PROFILING_EXTENSION_ALWAYS_ON = 'PROFILING_EXTENSION_ALWAYS_ON'; + public const PROFILING_EXTENSION_HTTP_KEY = 'PROFILING_EXTENSION_HTTP_KEY'; + // Database and Cache Configuration Variables public const DB_HOST = 'MYSQL_HOST'; public const DB_PORT = 'MYSQL_PORT'; @@ -290,4 +294,19 @@ class Environment 'db' => (int)($this->data[self::REDIS_DB] ?? 1), ]; } + + public function isProfilingExtensionEnabled(): bool + { + return (1 === (int)($this->data[self::PROFILING_EXTENSION_ENABLED] ?? 0)); + } + + public function isProfilingExtensionAlwaysOn(): bool + { + return (1 === (int)($this->data[self::PROFILING_EXTENSION_ALWAYS_ON] ?? 0)); + } + + public function getProfilingExtensionHttpKey(): string + { + return $this->data[self::PROFILING_EXTENSION_HTTP_KEY] ?? 'dev'; + } } diff --git a/src/MessageQueue/ResetArrayCacheMiddleware.php b/src/MessageQueue/ResetArrayCacheMiddleware.php new file mode 100644 index 000000000..3d75f926e --- /dev/null +++ b/src/MessageQueue/ResetArrayCacheMiddleware.php @@ -0,0 +1,37 @@ +cache = $cache; + } + + /** + * @inheritDoc + */ + public static function getSubscribedEvents() + { + return [ + WorkerMessageReceivedEvent::class => [ + ['resetArrayCache', -100], + ], + ]; + } + + public function resetArrayCache(WorkerMessageReceivedEvent $event): void + { + if ($this->cache instanceof ResettableInterface) { + $this->cache->reset(); + } + } +} diff --git a/src/Notification/Check/ProfilerAdvisorCheck.php b/src/Notification/Check/ProfilerAdvisorCheck.php new file mode 100644 index 000000000..cc87ee237 --- /dev/null +++ b/src/Notification/Check/ProfilerAdvisorCheck.php @@ -0,0 +1,68 @@ +environment = $environment; + } + + public function __invoke(GetNotifications $event): void + { + // This notification is for full administrators only. + $request = $event->getRequest(); + $acl = $request->getAcl(); + if (!$acl->isAllowed(Acl::GLOBAL_ALL)) { + return; + } + + if (!$this->environment->isDocker()) { + return; + } + + $profilerIsEnabled = $this->environment->isProfilingExtensionEnabled(); + if (!$profilerIsEnabled) { + return; + } + + $notification = new Notification(); + $notification->title = __('The performance profiling extension is currently enabled on this installation.'); + $notification->body = __( + 'You can track the execution time and memory usage of any AzuraCast page or application ' . + 'from the profiler page.', + ); + $notification->type = Flash::INFO; + + $notification->actionLabel = __('Profiler Control Panel'); + $notification->actionUrl = '/?' . http_build_query( + [ + 'SPX_UI_URI' => '/', + 'SPX_KEY' => $this->environment->getProfilingExtensionHttpKey(), + ] + ); + + $event->addNotification($notification); + + if ($this->environment->isProfilingExtensionAlwaysOn()) { + $notification = new Notification(); + $notification->title = __('Performance profiling is currently enabled for all requests.'); + $notification->body = __( + 'This can have an adverse impact on system performance. ' . + 'You should disable this when possible.' + ); + $notification->type = Flash::WARNING; + + $event->addNotification($notification); + } + } +}