From e2bef275ec9a5e8f96cc3348b98067e65e6bf3d5 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 23 Jan 2025 09:36:29 +0100 Subject: [PATCH 1/6] fix(taskprocessing): Cache result of getAvailableTaskTypes between requests Signed-off-by: Marcel Klehr --- lib/private/TaskProcessing/Manager.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 2f3ba02634d86..4e9dc7fd24ff2 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -31,6 +31,8 @@ use OCP\Files\NotPermittedException; use OCP\Files\SimpleFS\ISimpleFile; use OCP\Http\Client\IClientService; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IConfig; use OCP\IL10N; use OCP\IServerContainer; @@ -77,6 +79,8 @@ class Manager implements IManager { private ?array $availableTaskTypes = null; private IAppData $appData; + private ICache $cache; + public function __construct( private IConfig $config, private Coordinator $coordinator, @@ -91,8 +95,10 @@ public function __construct( private IUserMountCache $userMountCache, private IClientService $clientService, private IAppManager $appManager, + ICacheFactory $cacheFactory, ) { $this->appData = $appDataFactory->get('core'); + $this->cache = $cacheFactory->createLocal('task_processing::'); } @@ -582,10 +588,10 @@ private function _getTaskTypeSettings(): array { foreach ($taskTypes as $taskType) { $taskTypeSettings[$taskType->getId()] = false; }; - + return $taskTypeSettings; } - + } /** @@ -746,6 +752,9 @@ public function getPreferredProvider(string $taskTypeId) { } public function getAvailableTaskTypes(bool $showDisabled = false): array { + if ($this->availableTaskTypes === null) { + $this->availableTaskTypes = $this->cache->get('available_task_types'); + } // Either we have no cache or showDisabled is turned on, which we don't want to cache, ever. if ($this->availableTaskTypes === null || $showDisabled) { $taskTypes = $this->_getTaskTypes(); @@ -787,6 +796,7 @@ public function getAvailableTaskTypes(bool $showDisabled = false): array { } $this->availableTaskTypes = $availableTaskTypes; + $this->cache->set('available_task_types', $this->availableTaskTypes, 60); } From 8c81f9e0faf0de4adfa43115be51f0316a81eeb2 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Tue, 21 Jan 2025 20:05:51 +0100 Subject: [PATCH 2/6] fix(TaskProcessing\Manager): Cache the result of parsing JSON Signed-off-by: Marcel Klehr --- lib/private/TaskProcessing/Manager.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 4e9dc7fd24ff2..9439682642b39 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -79,6 +79,7 @@ class Manager implements IManager { private ?array $availableTaskTypes = null; private IAppData $appData; + private ?array $preferences = null; private ICache $cache; public function __construct( @@ -731,10 +732,10 @@ public function getProviders(): array { public function getPreferredProvider(string $taskTypeId) { try { - $preferences = json_decode($this->config->getAppValue('core', 'ai.taskprocessing_provider_preferences', 'null'), associative: true, flags: JSON_THROW_ON_ERROR); + $this->preferences = $this->preferences ?? json_decode($this->config->getAppValue('core', 'ai.taskprocessing_provider_preferences', 'null'), associative: true, flags: JSON_THROW_ON_ERROR); $providers = $this->getProviders(); - if (isset($preferences[$taskTypeId])) { - $provider = current(array_values(array_filter($providers, fn ($provider) => $provider->getId() === $preferences[$taskTypeId]))); + if (isset($this->preferences[$taskTypeId])) { + $provider = current(array_values(array_filter($providers, fn ($provider) => $provider->getId() === $this->preferences[$taskTypeId]))); if ($provider !== false) { return $provider; } From c88c2216aefd9ee3962d437a9913c496a1968e1f Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 23 Jan 2025 10:31:29 +0100 Subject: [PATCH 3/6] fix(taskprocessing): Fix tests Signed-off-by: Marcel Klehr --- tests/lib/TaskProcessing/TaskProcessingTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/lib/TaskProcessing/TaskProcessingTest.php b/tests/lib/TaskProcessing/TaskProcessingTest.php index 1088faa11268d..5dd38f83339fa 100644 --- a/tests/lib/TaskProcessing/TaskProcessingTest.php +++ b/tests/lib/TaskProcessing/TaskProcessingTest.php @@ -21,6 +21,7 @@ use OCP\Files\Config\IUserMountCache; use OCP\Files\IRootFolder; use OCP\Http\Client\IClientService; +use OCP\ICacheFactory; use OCP\IConfig; use OCP\IDBConnection; use OCP\IServerContainer; @@ -473,6 +474,7 @@ protected function setUp(): void { $this->userMountCache, \OC::$server->get(IClientService::class), \OC::$server->get(IAppManager::class), + \OC::$server->get(ICacheFactory::class), ); } From 215f6c6418c6482a841d84571e3b40c41c84f0e1 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 23 Jan 2025 10:40:42 +0100 Subject: [PATCH 4/6] fix(taskprocessing): cache provider settings in distributed cache as well Signed-off-by: Marcel Klehr --- lib/private/TaskProcessing/Manager.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 9439682642b39..439b8c3c74638 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -81,6 +81,7 @@ class Manager implements IManager { private IAppData $appData; private ?array $preferences = null; private ICache $cache; + private ICache $distributedCache; public function __construct( private IConfig $config, @@ -100,6 +101,7 @@ public function __construct( ) { $this->appData = $appDataFactory->get('core'); $this->cache = $cacheFactory->createLocal('task_processing::'); + $this->cache = $cacheFactory->createDistributed('task_processing::'); } @@ -732,7 +734,14 @@ public function getProviders(): array { public function getPreferredProvider(string $taskTypeId) { try { - $this->preferences = $this->preferences ?? json_decode($this->config->getAppValue('core', 'ai.taskprocessing_provider_preferences', 'null'), associative: true, flags: JSON_THROW_ON_ERROR); + if ($this->preferences === null) { + $this->preferences = $this->distributedCache->get('ai.taskprocessing_provider_preferences'); + if ($this->preferences === null) { + $this->preferences = json_decode($this->config->getAppValue('core', 'ai.taskprocessing_provider_preferences', 'null'), associative: true, flags: JSON_THROW_ON_ERROR); + $this->distributedCache->set('ai.taskprocessing_provider_preferences', $this->preferences, 60 * 3); + } + } + $providers = $this->getProviders(); if (isset($this->preferences[$taskTypeId])) { $provider = current(array_values(array_filter($providers, fn ($provider) => $provider->getId() === $this->preferences[$taskTypeId]))); @@ -754,6 +763,7 @@ public function getPreferredProvider(string $taskTypeId) { public function getAvailableTaskTypes(bool $showDisabled = false): array { if ($this->availableTaskTypes === null) { + // We use local cache only because distributed cache uses JSOn stringify which would botch our ShapeDescriptor objects $this->availableTaskTypes = $this->cache->get('available_task_types'); } // Either we have no cache or showDisabled is turned on, which we don't want to cache, ever. From 6e59f9a6930e56dafc2baaa1e6b0d4fc8a6c7fdc Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Thu, 23 Jan 2025 11:41:39 +0100 Subject: [PATCH 5/6] fix: copypasta Co-authored-by: Julien Veyssier Signed-off-by: Marcel Klehr --- lib/private/TaskProcessing/Manager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 439b8c3c74638..10224584b43c4 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -101,7 +101,7 @@ public function __construct( ) { $this->appData = $appDataFactory->get('core'); $this->cache = $cacheFactory->createLocal('task_processing::'); - $this->cache = $cacheFactory->createDistributed('task_processing::'); + $this->distributedCache = $cacheFactory->createDistributed('task_processing::'); } From 35052624b9c499659d71686526836c77f4e888a2 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Fri, 24 Jan 2025 10:12:56 +0100 Subject: [PATCH 6/6] fix(TaskProcessing): Cache providersById in getPreferredProviders Signed-off-by: Marcel Klehr --- lib/private/TaskProcessing/Manager.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php index 10224584b43c4..cb2434422aab6 100644 --- a/lib/private/TaskProcessing/Manager.php +++ b/lib/private/TaskProcessing/Manager.php @@ -80,6 +80,7 @@ class Manager implements IManager { private IAppData $appData; private ?array $preferences = null; + private ?array $providersById = null; private ICache $cache; private ICache $distributedCache; @@ -744,9 +745,13 @@ public function getPreferredProvider(string $taskTypeId) { $providers = $this->getProviders(); if (isset($this->preferences[$taskTypeId])) { - $provider = current(array_values(array_filter($providers, fn ($provider) => $provider->getId() === $this->preferences[$taskTypeId]))); - if ($provider !== false) { - return $provider; + $providersById = $this->providersById ?? array_reduce($providers, static function (array $carry, IProvider $provider) { + $carry[$provider->getId()] = $provider; + return $carry; + }, []); + $this->providersById = $providersById; + if (isset($providersById[$this->preferences[$taskTypeId]])) { + return $providersById[$this->preferences[$taskTypeId]]; } } // By default, use the first available provider