Skip to content

Commit 4483413

Browse files
implementation of recommendations
1 parent 8533696 commit 4483413

2 files changed

Lines changed: 53 additions & 13 deletions

File tree

docs/fr/worker.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,34 @@ FrankenPHP traitera les requêtes entrantes en quelques millisecondes.
55

66
## Avertissement sur la conception Stateful
77

8-
Contrairement au modèle PHP-FPM traditionnel, l'application reste chargée en mémoire entre les requêtes. Par conséquent, tout état stocké dans vos services (propriétés d'objet, singletons, etc.) sera conservé et partagé entre les requêtes successives traitées par le même worker. Cela peut entraîner des fuites de données et de mémoires ou des états incohérents si votre application n'est pas conçue pour cela.
9-
L'article suivant résume ce problème et explique comment y remédier, notamment pour les applications Symfony en utilisant ResetInterface pour garantir que vos services sont "réinitialisés" à chaque nouvelle requête.
8+
Contrairement au modèle PHP-FPM traditionnel, l'application reste **chargée en mémoire** entre les requêtes. Par conséquent, tout état stocké dans vos services (propriétés d'objet, singletons, etc.) sera conservé et partagé entre les requêtes successives traitées par le même worker. Cela peut entraîner des fuites de données et de mémoires ou des états incohérents si votre application n'est pas conçue pour cela.
109

11-
**Ressources supplémentaires :**
10+
### Concevoir une application Stateless
1211

13-
- Article (EN) : [Getting your Symfony app ready for Swoole, RoadRunner, and FrankenPHP](https://dev.to/sergiid/getting-symfony-app-ready-for-swoole-roadrunner-and-frankenphp-no-ai-involved-2d0g)
14-
- Symfony : La [documentation de Messenger](https://symfony.com/doc/current/messenger.html#stateless-worker) aborde également ce concept de "stateless worker".
15-
- Outil : [phanalist](https://github.com/denzyldick/phanalist) est un analyseur statique qui peut vous aider à détecter les services "stateful" dans votre code.
12+
Le défi est de gérer le cycle de vie de vos objets, en particulier ceux qui sont des instances partagées par le conteneur de dépendances.
13+
14+
Principes à respecter :
15+
16+
- **Éviter l'état global :** Les variables globales et les propriétés statiques ne doivent pas être modifiées.
17+
- **Prudence avec les services :** Évitez de stocker des valeurs via des setters ou de modifier les propriétés publiques d'un service partagé, car ces changements affecteront la prochaine requête.
18+
- **Priorité aux nouveaux objets :** Tout ce qui est lié à la requête ou aux paramètres utilisateur doit être retourné comme un nouvel objet pour chaque requête.
19+
20+
### Détection des problèmes (Analyse Statique)
21+
22+
Des outils d'analyse statique peuvent vous aider à identifier les services potentiellement stateful. Ces outils vérifient notamment :
23+
24+
- L'utilisation de propriétés publiques ou statiques mutables dans les services partagés.
25+
- L'usage de fonctions comme `die()` ou `exit()`.
26+
27+
Un outil notable est **[denzyldick/phanalist](https://github.com/denzyldick/phanalist)**. Après installation, vous pouvez l'exécuter spécifiquement avec la règle E0012 (pour "Service compatibility with Shared Memory Model") pour obtenir une liste des endroits problématiques dans votre code.
28+
29+
### L'interface de réinitialisation (Symfony)
30+
31+
L'approche idéale est de concevoir vos services pour qu'ils soient naturellement `stateless`.
32+
33+
Toutefois, dans les cas où il vous est difficile de rendre un service partagé complètement stateless (par exemple, un service avec un cache interne ou une configuration spécifique à la requête), vous pouvez utiliser l'interface `Symfony\Contracts\Service\ResetInterface`.
34+
35+
Lorsqu'un service implémente cette interface, sa méthode reset() est automatiquement appelée par le conteneur de services à la fin de chaque requête. Cela permet de nettoyer spécifiquement l'état interne du service (par exemple, vider un cache interne, réinitialiser des propriétés...).
1636

1737
## Démarrage des scripts workers
1838

docs/worker.md

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,36 @@
33
Boot your application once and keep it in memory.
44
FrankenPHP will handle incoming requests in a few milliseconds.
55

6-
## Warning about stateful design
6+
## Designing for Stateful Applications
77

8-
Unlike with the traditional PHP-FPM model, the application remains loaded in memory between requests. Consequently, any state stored in your services (object properties, singletons, etc.) will be preserved and shared across successive requests handled by the same worker. This can lead to data leaks and memory issues, or inconsistent states if your application is not designed for it.
9-
The following article summarizes this issue and explains how to fix it, notably for Symfony applications using ResetInterface to ensure your services are "reset" for every new request.
8+
Unlike the traditional PHP-FPM model, the application remains **loaded in memory** between requests. Consequently, any state stored within your services (object properties, singletons, etc.) will be retained and shared between successive requests handled by the same worker. This can lead to data and memory leaks or inconsistent states if your application is not designed for this.
109

11-
**Additional Resources:**
10+
### Designing a Stateless Application
1211

13-
- Article: [Getting your Symfony app ready for Swoole, RoadRunner, and FrankenPHP](https://dev.to/sergiid/getting-symfony-app-ready-for-swoole-roadrunner-and-frankenphp-no-ai-involved-2d0g)
14-
- Symfony: [The Messenger](https://symfony.com/doc/current/messenger.html#stateless-worker) documentation also discusses this "stateless worker" concept.
15-
- Tool: [phanalist](https://github.com/denzyldick/phanalist) is a static analyzer that can help you detect "stateful" services in your code.
12+
The challenge is managing the lifecycle of your objects, especially those that are shared instances by the dependency container.
13+
14+
**Key Principles to Follow:**
15+
16+
- **Avoid Global State:** Global variables and static properties must not be modified.
17+
- **Caution with Services:** Avoid storing values via setters or modifying public properties of a shared service, as these changes will affect the next request.
18+
- **Prioritize New Objects:** Anything tied to the request or user parameters must be returned as a new object for each request.
19+
20+
### Issue Detection (Static Analysis)
21+
22+
Static analysis tools can help you identify potentially stateful services. These tools primarily check for:
23+
24+
- The use of mutable public or static properties in shared services.
25+
- The use of functions like `die()` or `exit()`.
26+
27+
A notable tool is **[denzyldick/phanalist](https://github.com/denzyldick/phanalist)**. After installation, you can run it specifically with rule E0012 (for "Service compatibility with Shared Memory Model") to get a list of problematic areas in your code.
28+
29+
### The Reset Interface (Symfony)
30+
31+
The ideal approach is to design your services to be naturally **`stateless`**.
32+
33+
However, in cases where it is difficult to make a shared service completely stateless (e.g., a service with an internal cache or request-specific configuration), you can use the **`Symfony\Contracts\Service\ResetInterface`**.
34+
35+
When a service implements this interface, its `reset()` method is automatically called by the service container at the end of each request. This allows you to specifically clean up the service's internal state (e.g., emptying an internal cache, resetting properties...).
1636

1737
## Starting Worker Scripts
1838

0 commit comments

Comments
 (0)