veilletech.fr
17 oct. Feed du jour
#05 SYMFONY Article

Symfony 8.2 : #[Lock] verrouille un contrôleur

Un attribut remplace dix lignes, pas la réflexion sur la durée.

Symfony 8.2 ajoute l'attribut #[Lock] : une seule requête à la fois par clé sur un contrôleur, 409 Conflict pour les requêtes concurrentes, verrou partagé avec read: true, clés construites avec des marqueurs {nom}. Trois pièges : un TTL de 30 s non renouvelé, une option blocking sans délai, et un verrou pris avant #[IsGranted].

2 min de lectureintermédiairevidéo 1:19
Partager
Sommaire5 sections
  1. Ce qui se passe
  2. Comment ça marche
  3. Les trois pièges
  4. Que faire
  5. À retenir

Ce qui se passe

Certains contrôleurs ne doivent jamais s'exécuter deux fois en même temps : importer un catalogue, débiter une commande, vendre les dernières places d'une conférence. Le composant Lock le permet depuis longtemps, mais il fallait injecter la fabrique de verrous, construire la clé, acquérir le verrou, traiter le cas « déjà pris » et le libérer. Symfony 8.2 remplace cette mécanique par un seul attribut, #[Lock], disponible dès que le composant Lock est installé.

Comment ça marche

Le comportement par défaut : une seule requête à la fois par clé ; la requête concurrente reçoit un 409 Conflict.

Pour renouveler ou libérer le verrou soi-même, on ajoute un argument LockInterface (ou SharedLockInterface) : Symfony injecte le verrou acquis par l'attribut. Rendu nullable, l'argument vaut null quand il n'y en a pas, par exemple dans une sous-requête qui réutilise le verrou de la requête principale, ou quand l'option methods exclut la méthode HTTP courante.

PHP
use Symfony\Component\Lock\LockInterface;

#[Lock]
public function import(LockInterface $lock): Response
{
    // … traitement long
    $lock->refresh(); // repousse l'expiration
    // …
}

Exemple reconstitué d'après la description du billet : pour le nom exact des paramètres de l'attribut, se reporter à la documentation de Symfony 8.2.

Les trois pièges

  1. TTL de 30 secondes par défaut, sans renouvellement automatique. Si le verrou expire avant la fin du contrôleur, une autre requête peut l'acquérir.
  2. blocking n'a aucun délai propre : une requête en attente patiente aussi longtemps que le verrou est tenu.
  3. Le verrou est pris avant #[IsGranted], quel que soit l'ordre des attributs (idem pour #[RateLimit]). Un utilisateur sans droit peut recevoir un 409 au lieu d'un 403, ou attendre le verrou avant d'être refusé.

Que faire

Repérer les contrôleurs d'import, de paiement et de stock, poser l'attribut, et injecter le verrou dès qu'un traitement peut dépasser 30 secondes pour le renouveler.

Source : New in Symfony 8.2: Locking Controllers, blog Symfony, 16 octobre 2026.