Nouveau dans Symfony 8.2 (en développement). Pour empêcher deux requêtes de faire la même chose en même temps, il fallait injecter une LockFactory, créer le verrou, l'acquérir, renvoyer une erreur s'il était pris, et penser à le libérer. L'attribut #[Lock] fait tout cela pour un contrôleur.
#[Lock]
use Symfony\Component\HttpKernel\Attribute\Lock; #[Route('/catalogue/import', methods: ['POST'])] #[Lock('catalogue')] public function importer(): Response
- Tant qu'une requête tient le verrou, les autres reçoivent 409 Conflict. Avec
blocking: true, elles attendent leur tour. - Le verrou est libéré à la fin du contrôleur, ou une fois une
StreamedResponseentièrement envoyée. {nom}dans la clé est remplacé par le paramètre de routenom:#[Lock('ventes-{conference}')]donne un verrou par conférence.read: trueprend un verrou partagé : les lectures tournent ensemble, mais pas avec l'écriture qui tient la même clé.- Le verrou dure 30 secondes au plus (
ttl) ; Symfony ne le prolonge pas. Il est pris dès que le contrôleur est connu, avant même la vérification de#[IsGranted].
Le composant Lock doit être installé ; il se configure alors tout seul, avec des sémaphores si l'extension sysvsem est là, des verrous sur fichier sinon. Les verrous en lecture demandent un stockage qui les connaît (flock, Redis, PostgreSQL…) : ici, config/packages/lock.yaml impose flock.
À faire
CatalogueController importe et exporte le catalogue de chaque boutique. Un import réécrit le fichier du catalogue : deux imports simultanés mélangent leurs produits, et un export lu pendant un import en livre la moitié.
- Un seul import à la fois par boutique : un import concurrent reçoit 409.
- Les exports d'une même boutique tournent ensemble, mais pas en même temps qu'un import : celui des deux qui arrive en second reçoit 409.
- Le compte des produits, lui, reste toujours disponible.
L'import nocturne et l'export comptable, lancés hors de l'application, prennent déjà le verrou catalogue-{boutique} (catalogue-lyon pour Lyon) : utilisez la même clé.