diff --git a/app/config/variables.php b/app/config/variables.php index 5dd7196266..46a6c7d1e2 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -37,7 +37,7 @@ return [ [ 'name' => '_APP_LOCKING_ENABLED', 'description' => 'Enable distributed locking for platform writes. Locks coordinate concurrent updates across API pods so that read-modify-write operations on shared documents do not lose updates. By default, set to \'enabled\'. Set to \'disabled\' as an emergency kill switch — locks become no-ops (fail-open) and concurrent writes will race.', - 'introduction' => '1.10.0', + 'introduction' => '1.9.3', 'default' => 'enabled', 'required' => false, 'question' => '', diff --git a/app/init/resources.php b/app/init/resources.php index 4c3a684d4e..d3443ee337 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -325,10 +325,12 @@ $container->set('distributedLockOrFail', function (\Redis $redis, Telemetry $tel if (! $acquired) { $attempts->add(1, ['outcome' => 'contended', 'target' => $target]); - throw new AppwriteException( - AppwriteException::GENERAL_RESOURCE_LOCKED, - "Resource '{$key}' is currently being modified by another request. Please retry." - ); + // Don't pass a custom message — the catalog message in + // app/config/errors.php is reused so we don't leak the internal + // lock key (which embeds collection name and document id) into a + // user-facing 409 response. The telemetry attribute already + // carries the target collection for operator-side observability. + throw new AppwriteException(AppwriteException::GENERAL_RESOURCE_LOCKED); } $attempts->add(1, ['outcome' => 'acquired', 'target' => $target]); diff --git a/src/Appwrite/Platform/Modules/Project/Http/Project/Services/Update.php b/src/Appwrite/Platform/Modules/Project/Http/Project/Services/Update.php index e7b048b734..1126da8897 100644 --- a/src/Appwrite/Platform/Modules/Project/Http/Project/Services/Update.php +++ b/src/Appwrite/Platform/Modules/Project/Http/Project/Services/Update.php @@ -81,7 +81,7 @@ class Update extends Action // the read-modify-write window; re-read inside the lock so the // baseline reflects any update that landed between request init // and lock acquisition. - $project = $distributedLockOrFail("platform:project:{$project->getId()}", function () use ($project, $serviceId, $enabled, $dbForPlatform, $authorization) { + $project = $distributedLockOrFail("lock:platform:projects:{$project->getId()}", function () use ($project, $serviceId, $enabled, $dbForPlatform, $authorization) { $project = $authorization->skip(fn () => $dbForPlatform->getDocument('projects', $project->getId())); $services = $project->getAttribute('services', []);