Merge pull request #54196 from nextcloud/enh/noid/taskprocessing-lazy-config

[TaskProcessing] Load and store some config keys lazily
pull/54241/head
Joas Schilling 2025-08-05 12:28:34 +07:00 committed by GitHub
commit ff3043346a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 34 additions and 40 deletions

@ -12,20 +12,15 @@ use OCA\Settings\Settings\Admin\ArtificialIntelligence;
use OCP\AppFramework\Controller; use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting; use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Http\DataResponse;
use OCP\IConfig; use OCP\IAppConfig;
use OCP\IRequest; use OCP\IRequest;
class AISettingsController extends Controller { class AISettingsController extends Controller {
/**
* @param string $appName
* @param IRequest $request
* @param IConfig $config
*/
public function __construct( public function __construct(
$appName, $appName,
IRequest $request, IRequest $request,
private IConfig $config, private IAppConfig $appConfig,
) { ) {
parent::__construct($appName, $request); parent::__construct($appName, $request);
} }
@ -43,7 +38,7 @@ class AISettingsController extends Controller {
if (!isset($settings[$key])) { if (!isset($settings[$key])) {
continue; continue;
} }
$this->config->setAppValue('core', $key, json_encode($settings[$key])); $this->appConfig->setValueString('core', $key, json_encode($settings[$key]), lazy: in_array($key, \OC\TaskProcessing\Manager::LAZY_CONFIG_KEYS, true));
} }
return new DataResponse(); return new DataResponse();

@ -10,7 +10,7 @@ namespace OCA\Settings\Settings\Admin;
use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState; use OCP\AppFramework\Services\IInitialState;
use OCP\IConfig; use OCP\IAppConfig;
use OCP\IL10N; use OCP\IL10N;
use OCP\Settings\IDelegatedSettings; use OCP\Settings\IDelegatedSettings;
use OCP\SpeechToText\ISpeechToTextManager; use OCP\SpeechToText\ISpeechToTextManager;
@ -28,7 +28,7 @@ use Psr\Log\LoggerInterface;
class ArtificialIntelligence implements IDelegatedSettings { class ArtificialIntelligence implements IDelegatedSettings {
public function __construct( public function __construct(
private IConfig $config, private IAppConfig $appConfig,
private IL10N $l, private IL10N $l,
private IInitialState $initialState, private IInitialState $initialState,
private ITranslationManager $translationManager, private ITranslationManager $translationManager,
@ -145,7 +145,7 @@ class ArtificialIntelligence implements IDelegatedSettings {
]; ];
foreach ($settings as $key => $defaultValue) { foreach ($settings as $key => $defaultValue) {
$value = $defaultValue; $value = $defaultValue;
$json = $this->config->getAppValue('core', $key, ''); $json = $this->appConfig->getValueString('core', $key, '', lazy: in_array($key, \OC\TaskProcessing\Manager::LAZY_CONFIG_KEYS, true));
if ($json !== '') { if ($json !== '') {
try { try {
$value = json_decode($json, true, flags: JSON_THROW_ON_ERROR); $value = json_decode($json, true, flags: JSON_THROW_ON_ERROR);

@ -2018,11 +2018,6 @@
<code><![CDATA[getSettingsManager]]></code> <code><![CDATA[getSettingsManager]]></code>
</UndefinedInterfaceMethod> </UndefinedInterfaceMethod>
</file> </file>
<file src="apps/settings/lib/Controller/AISettingsController.php">
<DeprecatedMethod>
<code><![CDATA[setAppValue]]></code>
</DeprecatedMethod>
</file>
<file src="apps/settings/lib/Controller/AppSettingsController.php"> <file src="apps/settings/lib/Controller/AppSettingsController.php">
<DeprecatedMethod> <DeprecatedMethod>
<code><![CDATA[getAppValue]]></code> <code><![CDATA[getAppValue]]></code>
@ -2083,9 +2078,6 @@
continue; continue;
}]]></code> }]]></code>
</DeprecatedInterface> </DeprecatedInterface>
<DeprecatedMethod>
<code><![CDATA[getAppValue]]></code>
</DeprecatedMethod>
</file> </file>
<file src="apps/settings/lib/Settings/Admin/Security.php"> <file src="apps/settings/lib/Settings/Admin/Security.php">
<UndefinedInterfaceMethod> <UndefinedInterfaceMethod>
@ -3009,12 +3001,6 @@
<code><![CDATA[resetDelayForIP]]></code> <code><![CDATA[resetDelayForIP]]></code>
</DeprecatedMethod> </DeprecatedMethod>
</file> </file>
<file src="core/Command/TaskProcessing/EnabledCommand.php">
<DeprecatedMethod>
<code><![CDATA[getAppValue]]></code>
<code><![CDATA[setAppValue]]></code>
</DeprecatedMethod>
</file>
<file src="core/Command/Upgrade.php"> <file src="core/Command/Upgrade.php">
<DeprecatedMethod> <DeprecatedMethod>
<code><![CDATA[listen]]></code> <code><![CDATA[listen]]></code>

@ -7,7 +7,7 @@
namespace OC\Core\Command\TaskProcessing; namespace OC\Core\Command\TaskProcessing;
use OC\Core\Command\Base; use OC\Core\Command\Base;
use OCP\IConfig; use OCP\IAppConfig;
use OCP\TaskProcessing\IManager; use OCP\TaskProcessing\IManager;
use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
@ -16,7 +16,7 @@ use Symfony\Component\Console\Output\OutputInterface;
class EnabledCommand extends Base { class EnabledCommand extends Base {
public function __construct( public function __construct(
protected IManager $taskProcessingManager, protected IManager $taskProcessingManager,
private IConfig $config, private IAppConfig $appConfig,
) { ) {
parent::__construct(); parent::__construct();
} }
@ -41,7 +41,7 @@ class EnabledCommand extends Base {
protected function execute(InputInterface $input, OutputInterface $output): int { protected function execute(InputInterface $input, OutputInterface $output): int {
$enabled = (bool)$input->getArgument('enabled'); $enabled = (bool)$input->getArgument('enabled');
$taskType = $input->getArgument('task-type-id'); $taskType = $input->getArgument('task-type-id');
$json = $this->config->getAppValue('core', 'ai.taskprocessing_type_preferences'); $json = $this->appConfig->getValueString('core', 'ai.taskprocessing_type_preferences', lazy: true);
try { try {
if ($json === '') { if ($json === '') {
$taskTypeSettings = []; $taskTypeSettings = [];
@ -51,7 +51,7 @@ class EnabledCommand extends Base {
$taskTypeSettings[$taskType] = $enabled; $taskTypeSettings[$taskType] = $enabled;
$this->config->setAppValue('core', 'ai.taskprocessing_type_preferences', json_encode($taskTypeSettings)); $this->appConfig->setValueString('core', 'ai.taskprocessing_type_preferences', json_encode($taskTypeSettings), lazy: true);
$this->writeArrayInOutputFormat($input, $output, $taskTypeSettings); $this->writeArrayInOutputFormat($input, $output, $taskTypeSettings);
return 0; return 0;
} catch (\JsonException $e) { } catch (\JsonException $e) {

@ -31,9 +31,9 @@ use OCP\Files\Node;
use OCP\Files\NotPermittedException; use OCP\Files\NotPermittedException;
use OCP\Files\SimpleFS\ISimpleFile; use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Http\Client\IClientService; use OCP\Http\Client\IClientService;
use OCP\IAppConfig;
use OCP\ICache; use OCP\ICache;
use OCP\ICacheFactory; use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\IL10N; use OCP\IL10N;
use OCP\IServerContainer; use OCP\IServerContainer;
use OCP\IUserManager; use OCP\IUserManager;
@ -73,6 +73,11 @@ class Manager implements IManager {
public const LEGACY_PREFIX_TEXTTOIMAGE = 'legacy:TextToImage:'; public const LEGACY_PREFIX_TEXTTOIMAGE = 'legacy:TextToImage:';
public const LEGACY_PREFIX_SPEECHTOTEXT = 'legacy:SpeechToText:'; public const LEGACY_PREFIX_SPEECHTOTEXT = 'legacy:SpeechToText:';
public const LAZY_CONFIG_KEYS = [
'ai.taskprocessing_type_preferences',
'ai.taskprocessing_provider_preferences',
];
/** @var list<IProvider>|null */ /** @var list<IProvider>|null */
private ?array $providers = null; private ?array $providers = null;
@ -92,7 +97,7 @@ class Manager implements IManager {
private ?GetTaskProcessingProvidersEvent $eventResult = null; private ?GetTaskProcessingProvidersEvent $eventResult = null;
public function __construct( public function __construct(
private IConfig $config, private IAppConfig $appConfig,
private Coordinator $coordinator, private Coordinator $coordinator,
private IServerContainer $serverContainer, private IServerContainer $serverContainer,
private LoggerInterface $logger, private LoggerInterface $logger,
@ -630,7 +635,7 @@ class Manager implements IManager {
*/ */
private function _getTaskTypeSettings(): array { private function _getTaskTypeSettings(): array {
try { try {
$json = $this->config->getAppValue('core', 'ai.taskprocessing_type_preferences', ''); $json = $this->appConfig->getValueString('core', 'ai.taskprocessing_type_preferences', '', lazy: true);
if ($json === '') { if ($json === '') {
return []; return [];
} }
@ -788,7 +793,11 @@ class Manager implements IManager {
if ($this->preferences === null) { if ($this->preferences === null) {
$this->preferences = $this->distributedCache->get('ai.taskprocessing_provider_preferences'); $this->preferences = $this->distributedCache->get('ai.taskprocessing_provider_preferences');
if ($this->preferences === null) { 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->preferences = json_decode(
$this->appConfig->getValueString('core', 'ai.taskprocessing_provider_preferences', 'null', lazy: true),
associative: true,
flags: JSON_THROW_ON_ERROR,
);
$this->distributedCache->set('ai.taskprocessing_provider_preferences', $this->preferences, 60 * 3); $this->distributedCache->set('ai.taskprocessing_provider_preferences', $this->preferences, 60 * 3);
} }
} }
@ -889,7 +898,7 @@ class Manager implements IManager {
$user = $this->userManager->get($userId); $user = $this->userManager->get($userId);
} }
$guestsAllowed = $this->config->getAppValue('core', 'ai.taskprocessing_guests', 'false'); $guestsAllowed = $this->appConfig->getValueString('core', 'ai.taskprocessing_guests', 'false');
if ($guestsAllowed == 'true' || !class_exists(\OCA\Guests\UserBackend::class) || !($user->getBackend() instanceof \OCA\Guests\UserBackend)) { if ($guestsAllowed == 'true' || !class_exists(\OCA\Guests\UserBackend::class) || !($user->getBackend() instanceof \OCA\Guests\UserBackend)) {
return true; return true;
} }

@ -26,6 +26,7 @@ use OCP\TaskProcessing\Exception\ValidationException;
* @since 30.0.0 * @since 30.0.0
*/ */
interface IManager { interface IManager {
/** /**
* @since 30.0.0 * @since 30.0.0
*/ */

@ -24,6 +24,7 @@ use OCP\Files\Config\IUserMountCache;
use OCP\Files\File; use OCP\Files\File;
use OCP\Files\IRootFolder; use OCP\Files\IRootFolder;
use OCP\Http\Client\IClientService; use OCP\Http\Client\IClientService;
use OCP\IAppConfig;
use OCP\ICacheFactory; use OCP\ICacheFactory;
use OCP\IConfig; use OCP\IConfig;
use OCP\IDBConnection; use OCP\IDBConnection;
@ -535,6 +536,7 @@ class TaskProcessingTest extends \Test\TestCase {
private IUserMountCache $userMountCache; private IUserMountCache $userMountCache;
private IRootFolder $rootFolder; private IRootFolder $rootFolder;
private IConfig $config; private IConfig $config;
private IAppConfig $appConfig;
public const TEST_USER = 'testuser'; public const TEST_USER = 'testuser';
@ -600,8 +602,9 @@ class TaskProcessingTest extends \Test\TestCase {
$this->userMountCache = $this->createMock(IUserMountCache::class); $this->userMountCache = $this->createMock(IUserMountCache::class);
$this->config = Server::get(IConfig::class); $this->config = Server::get(IConfig::class);
$this->appConfig = Server::get(IAppConfig::class);
$this->manager = new Manager( $this->manager = new Manager(
$this->config, $this->appConfig,
$this->coordinator, $this->coordinator,
$this->serverContainer, $this->serverContainer,
Server::get(LoggerInterface::class), Server::get(LoggerInterface::class),
@ -641,7 +644,7 @@ class TaskProcessingTest extends \Test\TestCase {
$taskProcessingTypeSettings = [ $taskProcessingTypeSettings = [
TextToText::ID => false, TextToText::ID => false,
]; ];
$this->config->setAppValue('core', 'ai.taskprocessing_type_preferences', json_encode($taskProcessingTypeSettings)); $this->appConfig->setValueString('core', 'ai.taskprocessing_type_preferences', json_encode($taskProcessingTypeSettings), lazy: true);
self::assertCount(0, $this->manager->getAvailableTaskTypes()); self::assertCount(0, $this->manager->getAvailableTaskTypes());
self::assertCount(1, $this->manager->getAvailableTaskTypes(true)); self::assertCount(1, $this->manager->getAvailableTaskTypes(true));
self::assertTrue($this->manager->hasProviders()); self::assertTrue($this->manager->hasProviders());
@ -651,7 +654,7 @@ class TaskProcessingTest extends \Test\TestCase {
public function testProviderShouldBeRegisteredAndTaskFailValidation(): void { public function testProviderShouldBeRegisteredAndTaskFailValidation(): void {
$this->config->setAppValue('core', 'ai.taskprocessing_type_preferences', ''); $this->appConfig->setValueString('core', 'ai.taskprocessing_type_preferences', '', lazy: true);
$this->registrationContext->expects($this->any())->method('getTaskProcessingProviders')->willReturn([ $this->registrationContext->expects($this->any())->method('getTaskProcessingProviders')->willReturn([
new ServiceRegistration('test', BrokenSyncProvider::class) new ServiceRegistration('test', BrokenSyncProvider::class)
]); ]);
@ -797,7 +800,7 @@ class TaskProcessingTest extends \Test\TestCase {
$taskProcessingTypeSettings = [ $taskProcessingTypeSettings = [
TextToText::ID => true, TextToText::ID => true,
]; ];
$this->config->setAppValue('core', 'ai.taskprocessing_type_preferences', json_encode($taskProcessingTypeSettings)); $this->appConfig->setValueString('core', 'ai.taskprocessing_type_preferences', json_encode($taskProcessingTypeSettings), lazy: true);
self::assertCount(1, $this->manager->getAvailableTaskTypes()); self::assertCount(1, $this->manager->getAvailableTaskTypes());
@ -1239,7 +1242,7 @@ class TaskProcessingTest extends \Test\TestCase {
private function createManagerInstance(): Manager { private function createManagerInstance(): Manager {
// Clear potentially cached config values if needed // Clear potentially cached config values if needed
$this->config->deleteAppValue('core', 'ai.taskprocessing_type_preferences'); $this->appConfig->deleteKey('core', 'ai.taskprocessing_type_preferences');
// Re-create Text2ImageManager if its state matters or mocks change // Re-create Text2ImageManager if its state matters or mocks change
$text2imageManager = new \OC\TextToImage\Manager( $text2imageManager = new \OC\TextToImage\Manager(
@ -1253,7 +1256,7 @@ class TaskProcessingTest extends \Test\TestCase {
); );
return new Manager( return new Manager(
$this->config, $this->appConfig,
$this->coordinator, $this->coordinator,
$this->serverContainer, $this->serverContainer,
Server::get(LoggerInterface::class), Server::get(LoggerInterface::class),